Serenity Operating System
at portability 720 lines 16 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/ScopedValueRollback.h> 28#include <AK/String.h> 29#include <AK/Vector.h> 30#include <Kernel/Syscall.h> 31#include <alloca.h> 32#include <assert.h> 33#include <errno.h> 34#include <fcntl.h> 35#include <grp.h> 36#include <pwd.h> 37#include <stdarg.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <string.h> 41#include <sys/ioctl.h> 42#include <sys/types.h> 43#include <termios.h> 44#include <unistd.h> 45 46extern "C" { 47 48int systrace(pid_t pid) 49{ 50 int rc = syscall(SC_systrace, pid); 51 __RETURN_WITH_ERRNO(rc, rc, -1); 52} 53 54int chown(const char* pathname, uid_t uid, gid_t gid) 55{ 56 if (!pathname) { 57 errno = EFAULT; 58 return -1; 59 } 60 Syscall::SC_chown_params params { { pathname, strlen(pathname) }, uid, gid }; 61 int rc = syscall(SC_chown, &params); 62 __RETURN_WITH_ERRNO(rc, rc, -1); 63} 64 65int fchown(int fd, uid_t uid, gid_t gid) 66{ 67 int rc = syscall(SC_fchown, fd, uid, gid); 68 __RETURN_WITH_ERRNO(rc, rc, -1); 69} 70 71pid_t fork() 72{ 73 int rc = syscall(SC_fork); 74 __RETURN_WITH_ERRNO(rc, rc, -1); 75} 76 77int execv(const char* path, char* const argv[]) 78{ 79 return execve(path, argv, environ); 80} 81 82int execve(const char* filename, char* const argv[], char* const envp[]) 83{ 84 size_t arg_count = 0; 85 for (size_t i = 0; argv[i]; ++i) 86 ++arg_count; 87 88 size_t env_count = 0; 89 for (size_t i = 0; envp[i]; ++i) 90 ++env_count; 91 92 auto copy_strings = [&](auto& vec, size_t count, auto& output) { 93 output.length = count; 94 for (size_t i = 0; vec[i]; ++i) { 95 output.strings[i].characters = vec[i]; 96 output.strings[i].length = strlen(vec[i]); 97 } 98 }; 99 100 Syscall::SC_execve_params params; 101 params.arguments.strings = (Syscall::StringArgument*)alloca(arg_count * sizeof(Syscall::StringArgument)); 102 params.environment.strings = (Syscall::StringArgument*)alloca(env_count * sizeof(Syscall::StringArgument)); 103 104 params.path = { filename, strlen(filename) }; 105 copy_strings(argv, arg_count, params.arguments); 106 copy_strings(envp, env_count, params.environment); 107 108 int rc = syscall(SC_execve, &params); 109 __RETURN_WITH_ERRNO(rc, rc, -1); 110} 111 112int execvpe(const char* filename, char* const argv[], char* const envp[]) 113{ 114 if (strchr(filename, '/')) 115 return execve(filename, argv, envp); 116 117 ScopedValueRollback errno_rollback(errno); 118 String path = getenv("PATH"); 119 if (path.is_empty()) 120 path = "/bin:/usr/bin"; 121 auto parts = path.split(':'); 122 for (auto& part : parts) { 123 auto candidate = String::format("%s/%s", part.characters(), filename); 124 int rc = execve(candidate.characters(), argv, envp); 125 if (rc < 0 && errno != ENOENT) { 126 errno_rollback.set_override_rollback_value(errno); 127 dbg() << "execvpe() failed on attempt (" << candidate << ") with " << strerror(errno); 128 return rc; 129 } 130 } 131 errno_rollback.set_override_rollback_value(ENOENT); 132 dbg() << "execvpe() leaving :("; 133 return -1; 134} 135 136int execvp(const char* filename, char* const argv[]) 137{ 138 int rc = execvpe(filename, argv, environ); 139 dbg() << "execvp() about to return " << rc << " with errno=" << errno; 140 return rc; 141} 142 143int execl(const char* filename, const char* arg0, ...) 144{ 145 Vector<const char*, 16> args; 146 args.append(arg0); 147 148 va_list ap; 149 va_start(ap, arg0); 150 for (;;) { 151 const char* arg = va_arg(ap, const char*); 152 if (!arg) 153 break; 154 args.append(arg); 155 } 156 va_end(ap); 157 args.append(nullptr); 158 return execve(filename, const_cast<char* const*>(args.data()), environ); 159} 160 161int execlp(const char* filename, const char* arg0, ...) 162{ 163 Vector<const char*, 16> args; 164 args.append(arg0); 165 166 va_list ap; 167 va_start(ap, arg0); 168 for (;;) { 169 const char* arg = va_arg(ap, const char*); 170 if (!arg) 171 break; 172 args.append(arg); 173 } 174 va_end(ap); 175 args.append(nullptr); 176 return execvpe(filename, const_cast<char* const*>(args.data()), environ); 177} 178 179uid_t getuid() 180{ 181 return syscall(SC_getuid); 182} 183 184gid_t getgid() 185{ 186 return syscall(SC_getgid); 187} 188 189uid_t geteuid() 190{ 191 return syscall(SC_geteuid); 192} 193 194gid_t getegid() 195{ 196 return syscall(SC_getegid); 197} 198 199pid_t getpid() 200{ 201 return syscall(SC_getpid); 202} 203 204pid_t getppid() 205{ 206 return syscall(SC_getppid); 207} 208 209pid_t getsid(pid_t pid) 210{ 211 int rc = syscall(SC_getsid, pid); 212 __RETURN_WITH_ERRNO(rc, rc, -1); 213} 214 215pid_t setsid() 216{ 217 int rc = syscall(SC_setsid); 218 __RETURN_WITH_ERRNO(rc, rc, -1); 219} 220 221pid_t tcgetpgrp(int fd) 222{ 223 return ioctl(fd, TIOCGPGRP); 224} 225 226int tcsetpgrp(int fd, pid_t pgid) 227{ 228 return ioctl(fd, TIOCSPGRP, pgid); 229} 230 231int setpgid(pid_t pid, pid_t pgid) 232{ 233 int rc = syscall(SC_setpgid, pid, pgid); 234 __RETURN_WITH_ERRNO(rc, rc, -1); 235} 236 237pid_t getpgid(pid_t pid) 238{ 239 int rc = syscall(SC_getpgid, pid); 240 __RETURN_WITH_ERRNO(rc, rc, -1); 241} 242 243pid_t getpgrp() 244{ 245 int rc = syscall(SC_getpgrp); 246 __RETURN_WITH_ERRNO(rc, rc, -1); 247} 248 249ssize_t read(int fd, void* buf, size_t count) 250{ 251 int rc = syscall(SC_read, fd, buf, count); 252 __RETURN_WITH_ERRNO(rc, rc, -1); 253} 254 255ssize_t write(int fd, const void* buf, size_t count) 256{ 257 int rc = syscall(SC_write, fd, buf, count); 258 __RETURN_WITH_ERRNO(rc, rc, -1); 259} 260 261int ttyname_r(int fd, char* buffer, size_t size) 262{ 263 int rc = syscall(SC_ttyname_r, fd, buffer, size); 264 __RETURN_WITH_ERRNO(rc, rc, -1); 265} 266 267static char ttyname_buf[32]; 268char* ttyname(int fd) 269{ 270 if (ttyname_r(fd, ttyname_buf, sizeof(ttyname_buf)) < 0) 271 return nullptr; 272 return ttyname_buf; 273} 274 275int close(int fd) 276{ 277 int rc = syscall(SC_close, fd); 278 __RETURN_WITH_ERRNO(rc, rc, -1); 279} 280 281static int do_stat(const char* path, struct stat* statbuf, bool follow_symlinks) 282{ 283 if (!path) { 284 errno = EFAULT; 285 return -1; 286 } 287 Syscall::SC_stat_params params { { path, strlen(path) }, statbuf, follow_symlinks }; 288 int rc = syscall(SC_stat, &params); 289 __RETURN_WITH_ERRNO(rc, rc, -1); 290} 291 292int lstat(const char* path, struct stat* statbuf) 293{ 294 return do_stat(path, statbuf, false); 295} 296 297int stat(const char* path, struct stat* statbuf) 298{ 299 return do_stat(path, statbuf, true); 300} 301 302int fstat(int fd, struct stat* statbuf) 303{ 304 int rc = syscall(SC_fstat, fd, statbuf); 305 __RETURN_WITH_ERRNO(rc, rc, -1); 306} 307 308int chdir(const char* path) 309{ 310 if (!path) { 311 errno = EFAULT; 312 return -1; 313 } 314 int rc = syscall(SC_chdir, path, strlen(path)); 315 __RETURN_WITH_ERRNO(rc, rc, -1); 316} 317 318int fchdir(int fd) 319{ 320 int rc = syscall(SC_fchdir, fd); 321 __RETURN_WITH_ERRNO(rc, rc, -1); 322} 323 324char* getcwd(char* buffer, size_t size) 325{ 326 if (!buffer) { 327 size = size ? size : PATH_MAX; 328 buffer = (char*)malloc(size); 329 } 330 int rc = syscall(SC_getcwd, buffer, size); 331 __RETURN_WITH_ERRNO(rc, buffer, nullptr); 332} 333 334char* getwd(char* buf) 335{ 336 auto* p = getcwd(buf, PATH_MAX); 337 return p; 338} 339 340int sleep(unsigned seconds) 341{ 342 return syscall(SC_sleep, seconds); 343} 344 345int usleep(useconds_t usec) 346{ 347 return syscall(SC_usleep, usec); 348} 349 350int gethostname(char* buffer, size_t size) 351{ 352 int rc = syscall(SC_gethostname, buffer, size); 353 __RETURN_WITH_ERRNO(rc, rc, -1); 354} 355 356ssize_t readlink(const char* path, char* buffer, size_t size) 357{ 358 Syscall::SC_readlink_params params { { path, strlen(path) }, { buffer, size } }; 359 int rc = syscall(SC_readlink, &params); 360 __RETURN_WITH_ERRNO(rc, rc, -1); 361} 362 363off_t lseek(int fd, off_t offset, int whence) 364{ 365 int rc = syscall(SC_lseek, fd, offset, whence); 366 __RETURN_WITH_ERRNO(rc, rc, -1); 367} 368 369int link(const char* old_path, const char* new_path) 370{ 371 if (!old_path || !new_path) { 372 errno = EFAULT; 373 return -1; 374 } 375 Syscall::SC_link_params params { { old_path, strlen(old_path) }, { new_path, strlen(new_path) } }; 376 int rc = syscall(SC_link, &params); 377 __RETURN_WITH_ERRNO(rc, rc, -1); 378} 379 380int unlink(const char* pathname) 381{ 382 int rc = syscall(SC_unlink, pathname, strlen(pathname)); 383 __RETURN_WITH_ERRNO(rc, rc, -1); 384} 385 386int symlink(const char* target, const char* linkpath) 387{ 388 if (!target || !linkpath) { 389 errno = EFAULT; 390 return -1; 391 } 392 Syscall::SC_symlink_params params { { target, strlen(target) }, { linkpath, strlen(linkpath) } }; 393 int rc = syscall(SC_symlink, &params); 394 __RETURN_WITH_ERRNO(rc, rc, -1); 395} 396 397int rmdir(const char* pathname) 398{ 399 if (!pathname) { 400 errno = EFAULT; 401 return -1; 402 } 403 int rc = syscall(SC_rmdir, pathname, strlen(pathname)); 404 __RETURN_WITH_ERRNO(rc, rc, -1); 405} 406 407int isatty(int fd) 408{ 409 struct termios dummy; 410 return tcgetattr(fd, &dummy) == 0; 411} 412 413int getdtablesize() 414{ 415 int rc = syscall(SC_getdtablesize); 416 __RETURN_WITH_ERRNO(rc, rc, -1); 417} 418 419int dup(int old_fd) 420{ 421 int rc = syscall(SC_dup, old_fd); 422 __RETURN_WITH_ERRNO(rc, rc, -1); 423} 424 425int dup2(int old_fd, int new_fd) 426{ 427 int rc = syscall(SC_dup2, old_fd, new_fd); 428 __RETURN_WITH_ERRNO(rc, rc, -1); 429} 430 431int setgroups(size_t size, const gid_t* list) 432{ 433 int rc = syscall(SC_setgroups, size, list); 434 __RETURN_WITH_ERRNO(rc, rc, -1); 435} 436 437int getgroups(int size, gid_t list[]) 438{ 439 int rc = syscall(SC_getgroups, size, list); 440 __RETURN_WITH_ERRNO(rc, rc, -1); 441} 442 443int pipe(int pipefd[2]) 444{ 445 return pipe2(pipefd, 0); 446} 447 448int pipe2(int pipefd[2], int flags) 449{ 450 int rc = syscall(SC_pipe, pipefd, flags); 451 __RETURN_WITH_ERRNO(rc, rc, -1); 452} 453 454unsigned int alarm(unsigned int seconds) 455{ 456 return syscall(SC_alarm, seconds); 457} 458 459int setuid(uid_t uid) 460{ 461 int rc = syscall(SC_setuid, uid); 462 __RETURN_WITH_ERRNO(rc, rc, -1); 463} 464 465int setgid(uid_t gid) 466{ 467 int rc = syscall(SC_setgid, gid); 468 __RETURN_WITH_ERRNO(rc, rc, -1); 469} 470 471int access(const char* pathname, int mode) 472{ 473 if (!pathname) { 474 errno = EFAULT; 475 return -1; 476 } 477 int rc = syscall(SC_access, pathname, strlen(pathname), mode); 478 __RETURN_WITH_ERRNO(rc, rc, -1); 479} 480 481int mknod(const char* pathname, mode_t mode, dev_t dev) 482{ 483 if (!pathname) { 484 errno = EFAULT; 485 return -1; 486 } 487 Syscall::SC_mknod_params params { { pathname, strlen(pathname) }, mode, dev }; 488 int rc = syscall(SC_mknod, &params); 489 __RETURN_WITH_ERRNO(rc, rc, -1); 490} 491 492long fpathconf(int fd, int name) 493{ 494 (void)fd; 495 (void)name; 496 497 switch (name) { 498 case _PC_PATH_MAX: 499 return PATH_MAX; 500 case _PC_VDISABLE: 501 return _POSIX_VDISABLE; 502 } 503 504 ASSERT_NOT_REACHED(); 505} 506 507long pathconf(const char* path, int name) 508{ 509 (void)path; 510 511 switch (name) { 512 case _PC_PATH_MAX: 513 return PATH_MAX; 514 case _PC_PIPE_BUF: 515 return PIPE_BUF; 516 } 517 518 ASSERT_NOT_REACHED(); 519} 520 521void _exit(int status) 522{ 523 syscall(SC_exit, status); 524 ASSERT_NOT_REACHED(); 525} 526 527void sync() 528{ 529 syscall(SC_sync); 530} 531 532int create_shared_buffer(int size, void** buffer) 533{ 534 int rc = syscall(SC_create_shared_buffer, size, buffer); 535 __RETURN_WITH_ERRNO(rc, rc, -1); 536} 537 538int share_buffer_with(int shared_buffer_id, pid_t peer_pid) 539{ 540 int rc = syscall(SC_share_buffer_with, shared_buffer_id, peer_pid); 541 __RETURN_WITH_ERRNO(rc, rc, -1); 542} 543 544int share_buffer_globally(int shared_buffer_id) 545{ 546 int rc = syscall(SC_share_buffer_globally, shared_buffer_id); 547 __RETURN_WITH_ERRNO(rc, rc, -1); 548} 549 550int set_process_icon(int icon_id) 551{ 552 int rc = syscall(SC_set_process_icon, icon_id); 553 __RETURN_WITH_ERRNO(rc, rc, -1); 554} 555 556void* get_shared_buffer(int shared_buffer_id) 557{ 558 int rc = syscall(SC_get_shared_buffer, shared_buffer_id); 559 if (rc < 0 && -rc < EMAXERRNO) { 560 errno = -rc; 561 return (void*)-1; 562 } 563 return (void*)rc; 564} 565 566int release_shared_buffer(int shared_buffer_id) 567{ 568 int rc = syscall(SC_release_shared_buffer, shared_buffer_id); 569 __RETURN_WITH_ERRNO(rc, rc, -1); 570} 571 572int get_shared_buffer_size(int shared_buffer_id) 573{ 574 int rc = syscall(SC_get_shared_buffer_size, shared_buffer_id); 575 __RETURN_WITH_ERRNO(rc, rc, -1); 576} 577 578int seal_shared_buffer(int shared_buffer_id) 579{ 580 int rc = syscall(SC_seal_shared_buffer, shared_buffer_id); 581 __RETURN_WITH_ERRNO(rc, rc, -1); 582} 583 584char* getlogin() 585{ 586 static char __getlogin_buffer[256]; 587 if (auto* passwd = getpwuid(getuid())) { 588 strncpy(__getlogin_buffer, passwd->pw_name, sizeof(__getlogin_buffer)); 589 endpwent(); 590 return __getlogin_buffer; 591 } 592 endpwent(); 593 return nullptr; 594} 595 596int ftruncate(int fd, off_t length) 597{ 598 int rc = syscall(SC_ftruncate, fd, length); 599 __RETURN_WITH_ERRNO(rc, rc, -1); 600} 601 602int gettid() 603{ 604 return syscall(SC_gettid); 605} 606 607int donate(int tid) 608{ 609 int rc = syscall(SC_donate, tid); 610 __RETURN_WITH_ERRNO(rc, rc, -1); 611} 612 613void sysbeep() 614{ 615 syscall(SC_beep); 616} 617 618int fsync(int fd) 619{ 620 UNUSED_PARAM(fd); 621 dbgprintf("FIXME: Implement fsync()\n"); 622 return 0; 623} 624 625int halt() 626{ 627 int rc = syscall(SC_halt); 628 __RETURN_WITH_ERRNO(rc, rc, -1); 629} 630 631int reboot() 632{ 633 int rc = syscall(SC_reboot); 634 __RETURN_WITH_ERRNO(rc, rc, -1); 635} 636 637int mount(const char* source, const char* target, const char* fs_type, int flags) 638{ 639 if (!source || !target || !fs_type) { 640 errno = EFAULT; 641 return -1; 642 } 643 Syscall::SC_mount_params params { 644 { source, strlen(source) }, 645 { target, strlen(target) }, 646 { fs_type, strlen(fs_type) }, 647 flags 648 }; 649 int rc = syscall(SC_mount, &params); 650 __RETURN_WITH_ERRNO(rc, rc, -1); 651} 652 653int umount(const char* mountpoint) 654{ 655 int rc = syscall(SC_umount, mountpoint, strlen(mountpoint)); 656 __RETURN_WITH_ERRNO(rc, rc, -1); 657} 658 659void dump_backtrace() 660{ 661 syscall(SC_dump_backtrace); 662} 663 664int get_process_name(char* buffer, int buffer_size) 665{ 666 int rc = syscall(SC_get_process_name, buffer, buffer_size); 667 __RETURN_WITH_ERRNO(rc, rc, -1); 668} 669 670int chroot(const char* path) 671{ 672 return chroot_with_mount_flags(path, -1); 673} 674 675int chroot_with_mount_flags(const char* path, int mount_flags) 676{ 677 if (!path) { 678 errno = EFAULT; 679 return -1; 680 } 681 int rc = syscall(SC_chroot, path, strlen(path), mount_flags); 682 __RETURN_WITH_ERRNO(rc, rc, -1); 683} 684 685int pledge(const char* promises, const char* execpromises) 686{ 687 Syscall::SC_pledge_params params { 688 { promises, promises ? strlen(promises) : 0 }, 689 { execpromises, execpromises ? strlen(execpromises) : 0 } 690 }; 691 int rc = syscall(SC_pledge, &params); 692 __RETURN_WITH_ERRNO(rc, rc, -1); 693} 694 695int unveil(const char* path, const char* permissions) 696{ 697 Syscall::SC_unveil_params params { 698 { path, path ? strlen(path) : 0 }, 699 { permissions, permissions ? strlen(permissions) : 0 } 700 }; 701 int rc = syscall(SC_unveil, &params); 702 __RETURN_WITH_ERRNO(rc, rc, -1); 703} 704 705ssize_t pread(int fd, void* buf, size_t count, off_t offset) 706{ 707 // FIXME: This is not thread safe and should be implemented in the kernel instead. 708 off_t old_offset = lseek(fd, 0, SEEK_CUR); 709 lseek(fd, offset, SEEK_SET); 710 ssize_t nread = read(fd, buf, count); 711 lseek(fd, old_offset, SEEK_SET); 712 return nread; 713} 714 715char* getpass(const char* prompt) 716{ 717 dbg() << "FIXME: getpass(\"" << prompt << "\")"; 718 ASSERT_NOT_REACHED(); 719} 720}