Serenity Operating System
at hosted 669 lines 15 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 chown(const char* pathname, uid_t uid, gid_t gid) 49{ 50 if (!pathname) { 51 errno = EFAULT; 52 return -1; 53 } 54 Syscall::SC_chown_params params { { pathname, strlen(pathname) }, uid, gid }; 55 int rc = syscall(SC_chown, &params); 56 __RETURN_WITH_ERRNO(rc, rc, -1); 57} 58 59int fchown(int fd, uid_t uid, gid_t gid) 60{ 61 int rc = syscall(SC_fchown, fd, uid, gid); 62 __RETURN_WITH_ERRNO(rc, rc, -1); 63} 64 65pid_t fork() 66{ 67 int rc = syscall(SC_fork); 68 __RETURN_WITH_ERRNO(rc, rc, -1); 69} 70 71int execv(const char* path, char* const argv[]) 72{ 73 return execve(path, argv, environ); 74} 75 76int execve(const char* filename, char* const argv[], char* const envp[]) 77{ 78 size_t arg_count = 0; 79 for (size_t i = 0; argv[i]; ++i) 80 ++arg_count; 81 82 size_t env_count = 0; 83 for (size_t i = 0; envp[i]; ++i) 84 ++env_count; 85 86 auto copy_strings = [&](auto& vec, size_t count, auto& output) { 87 output.length = count; 88 for (size_t i = 0; vec[i]; ++i) { 89 output.strings[i].characters = vec[i]; 90 output.strings[i].length = strlen(vec[i]); 91 } 92 }; 93 94 Syscall::SC_execve_params params; 95 params.arguments.strings = (Syscall::StringArgument*)alloca(arg_count * sizeof(Syscall::StringArgument)); 96 params.environment.strings = (Syscall::StringArgument*)alloca(env_count * sizeof(Syscall::StringArgument)); 97 98 params.path = { filename, strlen(filename) }; 99 copy_strings(argv, arg_count, params.arguments); 100 copy_strings(envp, env_count, params.environment); 101 102 int rc = syscall(SC_execve, &params); 103 __RETURN_WITH_ERRNO(rc, rc, -1); 104} 105 106int execvpe(const char* filename, char* const argv[], char* const envp[]) 107{ 108 if (strchr(filename, '/')) 109 return execve(filename, argv, envp); 110 111 ScopedValueRollback errno_rollback(errno); 112 String path = getenv("PATH"); 113 if (path.is_empty()) 114 path = "/bin:/usr/bin"; 115 auto parts = path.split(':'); 116 for (auto& part : parts) { 117 auto candidate = String::format("%s/%s", part.characters(), filename); 118 int rc = execve(candidate.characters(), argv, envp); 119 if (rc < 0 && errno != ENOENT) { 120 errno_rollback.set_override_rollback_value(errno); 121 dbg() << "execvpe() failed on attempt (" << candidate << ") with " << strerror(errno); 122 return rc; 123 } 124 } 125 errno_rollback.set_override_rollback_value(ENOENT); 126 dbg() << "execvpe() leaving :("; 127 return -1; 128} 129 130int execvp(const char* filename, char* const argv[]) 131{ 132 int rc = execvpe(filename, argv, environ); 133 dbg() << "execvp() about to return " << rc << " with errno=" << errno; 134 return rc; 135} 136 137int execl(const char* filename, const char* arg0, ...) 138{ 139 Vector<const char*, 16> args; 140 args.append(arg0); 141 142 va_list ap; 143 va_start(ap, arg0); 144 for (;;) { 145 const char* arg = va_arg(ap, const char*); 146 if (!arg) 147 break; 148 args.append(arg); 149 } 150 va_end(ap); 151 args.append(nullptr); 152 return execve(filename, const_cast<char* const*>(args.data()), environ); 153} 154 155int execlp(const char* filename, const char* arg0, ...) 156{ 157 Vector<const char*, 16> args; 158 args.append(arg0); 159 160 va_list ap; 161 va_start(ap, arg0); 162 for (;;) { 163 const char* arg = va_arg(ap, const char*); 164 if (!arg) 165 break; 166 args.append(arg); 167 } 168 va_end(ap); 169 args.append(nullptr); 170 return execvpe(filename, const_cast<char* const*>(args.data()), environ); 171} 172 173uid_t getuid() 174{ 175 return syscall(SC_getuid); 176} 177 178gid_t getgid() 179{ 180 return syscall(SC_getgid); 181} 182 183uid_t geteuid() 184{ 185 return syscall(SC_geteuid); 186} 187 188gid_t getegid() 189{ 190 return syscall(SC_getegid); 191} 192 193pid_t getpid() 194{ 195 return syscall(SC_getpid); 196} 197 198pid_t getppid() 199{ 200 return syscall(SC_getppid); 201} 202 203pid_t getsid(pid_t pid) 204{ 205 int rc = syscall(SC_getsid, pid); 206 __RETURN_WITH_ERRNO(rc, rc, -1); 207} 208 209pid_t setsid() 210{ 211 int rc = syscall(SC_setsid); 212 __RETURN_WITH_ERRNO(rc, rc, -1); 213} 214 215pid_t tcgetpgrp(int fd) 216{ 217 return ioctl(fd, TIOCGPGRP); 218} 219 220int tcsetpgrp(int fd, pid_t pgid) 221{ 222 return ioctl(fd, TIOCSPGRP, pgid); 223} 224 225int setpgid(pid_t pid, pid_t pgid) 226{ 227 int rc = syscall(SC_setpgid, pid, pgid); 228 __RETURN_WITH_ERRNO(rc, rc, -1); 229} 230 231pid_t getpgid(pid_t pid) 232{ 233 int rc = syscall(SC_getpgid, pid); 234 __RETURN_WITH_ERRNO(rc, rc, -1); 235} 236 237pid_t getpgrp() 238{ 239 int rc = syscall(SC_getpgrp); 240 __RETURN_WITH_ERRNO(rc, rc, -1); 241} 242 243ssize_t read(int fd, void* buf, size_t count) 244{ 245 int rc = syscall(SC_read, fd, buf, count); 246 __RETURN_WITH_ERRNO(rc, rc, -1); 247} 248 249ssize_t write(int fd, const void* buf, size_t count) 250{ 251 int rc = syscall(SC_write, fd, buf, count); 252 __RETURN_WITH_ERRNO(rc, rc, -1); 253} 254 255int ttyname_r(int fd, char* buffer, size_t size) 256{ 257 int rc = syscall(SC_ttyname_r, fd, buffer, size); 258 __RETURN_WITH_ERRNO(rc, rc, -1); 259} 260 261static char ttyname_buf[32]; 262char* ttyname(int fd) 263{ 264 if (ttyname_r(fd, ttyname_buf, sizeof(ttyname_buf)) < 0) 265 return nullptr; 266 return ttyname_buf; 267} 268 269int close(int fd) 270{ 271 int rc = syscall(SC_close, fd); 272 __RETURN_WITH_ERRNO(rc, rc, -1); 273} 274 275static int do_stat(const char* path, struct stat* statbuf, bool follow_symlinks) 276{ 277 if (!path) { 278 errno = EFAULT; 279 return -1; 280 } 281 Syscall::SC_stat_params params { { path, strlen(path) }, statbuf, follow_symlinks }; 282 int rc = syscall(SC_stat, &params); 283 __RETURN_WITH_ERRNO(rc, rc, -1); 284} 285 286int lstat(const char* path, struct stat* statbuf) 287{ 288 return do_stat(path, statbuf, false); 289} 290 291int stat(const char* path, struct stat* statbuf) 292{ 293 return do_stat(path, statbuf, true); 294} 295 296int fstat(int fd, struct stat* statbuf) 297{ 298 int rc = syscall(SC_fstat, fd, statbuf); 299 __RETURN_WITH_ERRNO(rc, rc, -1); 300} 301 302int chdir(const char* path) 303{ 304 if (!path) { 305 errno = EFAULT; 306 return -1; 307 } 308 int rc = syscall(SC_chdir, path, strlen(path)); 309 __RETURN_WITH_ERRNO(rc, rc, -1); 310} 311 312int fchdir(int fd) 313{ 314 int rc = syscall(SC_fchdir, fd); 315 __RETURN_WITH_ERRNO(rc, rc, -1); 316} 317 318char* getcwd(char* buffer, size_t size) 319{ 320 if (!buffer) { 321 size = size ? size : PATH_MAX; 322 buffer = (char*)malloc(size); 323 } 324 int rc = syscall(SC_getcwd, buffer, size); 325 __RETURN_WITH_ERRNO(rc, buffer, nullptr); 326} 327 328char* getwd(char* buf) 329{ 330 auto* p = getcwd(buf, PATH_MAX); 331 return p; 332} 333 334int sleep(unsigned seconds) 335{ 336 return syscall(SC_sleep, seconds); 337} 338 339int usleep(useconds_t usec) 340{ 341 return syscall(SC_usleep, usec); 342} 343 344int gethostname(char* buffer, size_t size) 345{ 346 int rc = syscall(SC_gethostname, buffer, size); 347 __RETURN_WITH_ERRNO(rc, rc, -1); 348} 349 350ssize_t readlink(const char* path, char* buffer, size_t size) 351{ 352 Syscall::SC_readlink_params params { { path, strlen(path) }, { buffer, size } }; 353 int rc = syscall(SC_readlink, &params); 354 __RETURN_WITH_ERRNO(rc, rc, -1); 355} 356 357off_t lseek(int fd, off_t offset, int whence) 358{ 359 int rc = syscall(SC_lseek, fd, offset, whence); 360 __RETURN_WITH_ERRNO(rc, rc, -1); 361} 362 363int link(const char* old_path, const char* new_path) 364{ 365 if (!old_path || !new_path) { 366 errno = EFAULT; 367 return -1; 368 } 369 Syscall::SC_link_params params { { old_path, strlen(old_path) }, { new_path, strlen(new_path) } }; 370 int rc = syscall(SC_link, &params); 371 __RETURN_WITH_ERRNO(rc, rc, -1); 372} 373 374int unlink(const char* pathname) 375{ 376 int rc = syscall(SC_unlink, pathname, strlen(pathname)); 377 __RETURN_WITH_ERRNO(rc, rc, -1); 378} 379 380int symlink(const char* target, const char* linkpath) 381{ 382 if (!target || !linkpath) { 383 errno = EFAULT; 384 return -1; 385 } 386 Syscall::SC_symlink_params params { { target, strlen(target) }, { linkpath, strlen(linkpath) } }; 387 int rc = syscall(SC_symlink, &params); 388 __RETURN_WITH_ERRNO(rc, rc, -1); 389} 390 391int rmdir(const char* pathname) 392{ 393 if (!pathname) { 394 errno = EFAULT; 395 return -1; 396 } 397 int rc = syscall(SC_rmdir, pathname, strlen(pathname)); 398 __RETURN_WITH_ERRNO(rc, rc, -1); 399} 400 401int isatty(int fd) 402{ 403 struct termios dummy; 404 return tcgetattr(fd, &dummy) == 0; 405} 406 407int getdtablesize() 408{ 409 int rc = syscall(SC_getdtablesize); 410 __RETURN_WITH_ERRNO(rc, rc, -1); 411} 412 413int dup(int old_fd) 414{ 415 int rc = syscall(SC_dup, old_fd); 416 __RETURN_WITH_ERRNO(rc, rc, -1); 417} 418 419int dup2(int old_fd, int new_fd) 420{ 421 int rc = syscall(SC_dup2, old_fd, new_fd); 422 __RETURN_WITH_ERRNO(rc, rc, -1); 423} 424 425int setgroups(size_t size, const gid_t* list) 426{ 427 int rc = syscall(SC_setgroups, size, list); 428 __RETURN_WITH_ERRNO(rc, rc, -1); 429} 430 431int getgroups(int size, gid_t list[]) 432{ 433 int rc = syscall(SC_getgroups, size, list); 434 __RETURN_WITH_ERRNO(rc, rc, -1); 435} 436 437int pipe(int pipefd[2]) 438{ 439 return pipe2(pipefd, 0); 440} 441 442int pipe2(int pipefd[2], int flags) 443{ 444 int rc = syscall(SC_pipe, pipefd, flags); 445 __RETURN_WITH_ERRNO(rc, rc, -1); 446} 447 448unsigned int alarm(unsigned int seconds) 449{ 450 return syscall(SC_alarm, seconds); 451} 452 453int setuid(uid_t uid) 454{ 455 int rc = syscall(SC_setuid, uid); 456 __RETURN_WITH_ERRNO(rc, rc, -1); 457} 458 459int setgid(uid_t gid) 460{ 461 int rc = syscall(SC_setgid, gid); 462 __RETURN_WITH_ERRNO(rc, rc, -1); 463} 464 465int access(const char* pathname, int mode) 466{ 467 if (!pathname) { 468 errno = EFAULT; 469 return -1; 470 } 471 int rc = syscall(SC_access, pathname, strlen(pathname), mode); 472 __RETURN_WITH_ERRNO(rc, rc, -1); 473} 474 475int mknod(const char* pathname, mode_t mode, dev_t dev) 476{ 477 if (!pathname) { 478 errno = EFAULT; 479 return -1; 480 } 481 Syscall::SC_mknod_params params { { pathname, strlen(pathname) }, mode, dev }; 482 int rc = syscall(SC_mknod, &params); 483 __RETURN_WITH_ERRNO(rc, rc, -1); 484} 485 486long fpathconf(int fd, int name) 487{ 488 (void)fd; 489 (void)name; 490 491 switch (name) { 492 case _PC_PATH_MAX: 493 return PATH_MAX; 494 case _PC_VDISABLE: 495 return _POSIX_VDISABLE; 496 } 497 498 ASSERT_NOT_REACHED(); 499} 500 501long pathconf(const char* path, int name) 502{ 503 (void)path; 504 505 switch (name) { 506 case _PC_PATH_MAX: 507 return PATH_MAX; 508 case _PC_PIPE_BUF: 509 return PIPE_BUF; 510 } 511 512 ASSERT_NOT_REACHED(); 513} 514 515void _exit(int status) 516{ 517 syscall(SC_exit, status); 518 ASSERT_NOT_REACHED(); 519} 520 521void sync() 522{ 523 syscall(SC_sync); 524} 525 526int set_process_icon(int icon_id) 527{ 528 int rc = syscall(SC_set_process_icon, icon_id); 529 __RETURN_WITH_ERRNO(rc, rc, -1); 530} 531 532char* getlogin() 533{ 534 static char __getlogin_buffer[256]; 535 if (auto* passwd = getpwuid(getuid())) { 536 strncpy(__getlogin_buffer, passwd->pw_name, sizeof(__getlogin_buffer)); 537 endpwent(); 538 return __getlogin_buffer; 539 } 540 endpwent(); 541 return nullptr; 542} 543 544int ftruncate(int fd, off_t length) 545{ 546 int rc = syscall(SC_ftruncate, fd, length); 547 __RETURN_WITH_ERRNO(rc, rc, -1); 548} 549 550int gettid() 551{ 552 return syscall(SC_gettid); 553} 554 555int donate(int tid) 556{ 557 int rc = syscall(SC_donate, tid); 558 __RETURN_WITH_ERRNO(rc, rc, -1); 559} 560 561void sysbeep() 562{ 563 syscall(SC_beep); 564} 565 566int fsync(int fd) 567{ 568 UNUSED_PARAM(fd); 569 dbgprintf("FIXME: Implement fsync()\n"); 570 return 0; 571} 572 573int halt() 574{ 575 int rc = syscall(SC_halt); 576 __RETURN_WITH_ERRNO(rc, rc, -1); 577} 578 579int reboot() 580{ 581 int rc = syscall(SC_reboot); 582 __RETURN_WITH_ERRNO(rc, rc, -1); 583} 584 585int mount(int source_fd, const char* target, const char* fs_type, int flags) 586{ 587 if (!target || !fs_type) { 588 errno = EFAULT; 589 return -1; 590 } 591 592 Syscall::SC_mount_params params { 593 source_fd, 594 { target, strlen(target) }, 595 { fs_type, strlen(fs_type) }, 596 flags 597 }; 598 int rc = syscall(SC_mount, &params); 599 __RETURN_WITH_ERRNO(rc, rc, -1); 600} 601 602int umount(const char* mountpoint) 603{ 604 int rc = syscall(SC_umount, mountpoint, strlen(mountpoint)); 605 __RETURN_WITH_ERRNO(rc, rc, -1); 606} 607 608void dump_backtrace() 609{ 610 syscall(SC_dump_backtrace); 611} 612 613int get_process_name(char* buffer, int buffer_size) 614{ 615 int rc = syscall(SC_get_process_name, buffer, buffer_size); 616 __RETURN_WITH_ERRNO(rc, rc, -1); 617} 618 619int chroot(const char* path) 620{ 621 return chroot_with_mount_flags(path, -1); 622} 623 624int chroot_with_mount_flags(const char* path, int mount_flags) 625{ 626 if (!path) { 627 errno = EFAULT; 628 return -1; 629 } 630 int rc = syscall(SC_chroot, path, strlen(path), mount_flags); 631 __RETURN_WITH_ERRNO(rc, rc, -1); 632} 633 634int pledge(const char* promises, const char* execpromises) 635{ 636 Syscall::SC_pledge_params params { 637 { promises, promises ? strlen(promises) : 0 }, 638 { execpromises, execpromises ? strlen(execpromises) : 0 } 639 }; 640 int rc = syscall(SC_pledge, &params); 641 __RETURN_WITH_ERRNO(rc, rc, -1); 642} 643 644int unveil(const char* path, const char* permissions) 645{ 646 Syscall::SC_unveil_params params { 647 { path, path ? strlen(path) : 0 }, 648 { permissions, permissions ? strlen(permissions) : 0 } 649 }; 650 int rc = syscall(SC_unveil, &params); 651 __RETURN_WITH_ERRNO(rc, rc, -1); 652} 653 654ssize_t pread(int fd, void* buf, size_t count, off_t offset) 655{ 656 // FIXME: This is not thread safe and should be implemented in the kernel instead. 657 off_t old_offset = lseek(fd, 0, SEEK_CUR); 658 lseek(fd, offset, SEEK_SET); 659 ssize_t nread = read(fd, buf, count); 660 lseek(fd, old_offset, SEEK_SET); 661 return nread; 662} 663 664char* getpass(const char* prompt) 665{ 666 dbg() << "FIXME: getpass(\"" << prompt << "\")"; 667 ASSERT_NOT_REACHED(); 668} 669}