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