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