1 //===-- File.cpp ----------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Host/File.h" 10 11 #include <cerrno> 12 #include <climits> 13 #include <cstdarg> 14 #include <cstdio> 15 #include <fcntl.h> 16 17 #ifdef _WIN32 18 #include "lldb/Host/windows/windows.h" 19 #else 20 #include <sys/ioctl.h> 21 #include <sys/stat.h> 22 #include <termios.h> 23 #include <unistd.h> 24 #endif 25 26 #include "llvm/Support/ConvertUTF.h" 27 #include "llvm/Support/Errno.h" 28 #include "llvm/Support/FileSystem.h" 29 #include "llvm/Support/Process.h" 30 31 #include "lldb/Host/Config.h" 32 #include "lldb/Host/FileSystem.h" 33 #include "lldb/Host/Host.h" 34 #include "lldb/Utility/DataBufferHeap.h" 35 #include "lldb/Utility/FileSpec.h" 36 #include "lldb/Utility/Log.h" 37 38 using namespace lldb; 39 using namespace lldb_private; 40 using llvm::Expected; 41 42 Expected<const char *> 43 File::GetStreamOpenModeFromOptions(File::OpenOptions options) { 44 File::OpenOptions rw = 45 options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly | 46 File::eOpenOptionReadWrite); 47 48 if (options & File::eOpenOptionAppend) { 49 if (rw == File::eOpenOptionReadWrite) { 50 if (options & File::eOpenOptionCanCreateNewOnly) 51 return "a+x"; 52 else 53 return "a+"; 54 } else if (rw == File::eOpenOptionWriteOnly) { 55 if (options & File::eOpenOptionCanCreateNewOnly) 56 return "ax"; 57 else 58 return "a"; 59 } 60 } else if (rw == File::eOpenOptionReadWrite) { 61 if (options & File::eOpenOptionCanCreate) { 62 if (options & File::eOpenOptionCanCreateNewOnly) 63 return "w+x"; 64 else 65 return "w+"; 66 } else 67 return "r+"; 68 } else if (rw == File::eOpenOptionWriteOnly) { 69 return "w"; 70 } else if (rw == File::eOpenOptionReadOnly) { 71 return "r"; 72 } 73 return llvm::createStringError( 74 llvm::inconvertibleErrorCode(), 75 "invalid options, cannot convert to mode string"); 76 } 77 78 Expected<File::OpenOptions> File::GetOptionsFromMode(llvm::StringRef mode) { 79 OpenOptions opts = 80 llvm::StringSwitch<OpenOptions>(mode) 81 .Cases("r", "rb", eOpenOptionReadOnly) 82 .Cases("w", "wb", eOpenOptionWriteOnly) 83 .Cases("a", "ab", 84 eOpenOptionWriteOnly | eOpenOptionAppend | 85 eOpenOptionCanCreate) 86 .Cases("r+", "rb+", "r+b", eOpenOptionReadWrite) 87 .Cases("w+", "wb+", "w+b", 88 eOpenOptionReadWrite | eOpenOptionCanCreate | 89 eOpenOptionTruncate) 90 .Cases("a+", "ab+", "a+b", 91 eOpenOptionReadWrite | eOpenOptionAppend | 92 eOpenOptionCanCreate) 93 .Default(eOpenOptionInvalid); 94 if (opts != eOpenOptionInvalid) 95 return opts; 96 return llvm::createStringError( 97 llvm::inconvertibleErrorCode(), 98 "invalid mode, cannot convert to File::OpenOptions"); 99 } 100 101 int File::kInvalidDescriptor = -1; 102 FILE *File::kInvalidStream = nullptr; 103 104 Status File::Read(void *buf, size_t &num_bytes) { 105 return std::error_code(ENOTSUP, std::system_category()); 106 } 107 Status File::Write(const void *buf, size_t &num_bytes) { 108 return std::error_code(ENOTSUP, std::system_category()); 109 } 110 111 bool File::IsValid() const { return false; } 112 113 Status File::Close() { return Flush(); } 114 115 IOObject::WaitableHandle File::GetWaitableHandle() { 116 return IOObject::kInvalidHandleValue; 117 } 118 119 Status File::GetFileSpec(FileSpec &file_spec) const { 120 file_spec.Clear(); 121 return std::error_code(ENOTSUP, std::system_category()); 122 } 123 124 int File::GetDescriptor() const { return kInvalidDescriptor; } 125 126 FILE *File::GetStream() { return nullptr; } 127 128 off_t File::SeekFromStart(off_t offset, Status *error_ptr) { 129 if (error_ptr) 130 *error_ptr = std::error_code(ENOTSUP, std::system_category()); 131 return -1; 132 } 133 134 off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) { 135 if (error_ptr) 136 *error_ptr = std::error_code(ENOTSUP, std::system_category()); 137 return -1; 138 } 139 140 off_t File::SeekFromEnd(off_t offset, Status *error_ptr) { 141 if (error_ptr) 142 *error_ptr = std::error_code(ENOTSUP, std::system_category()); 143 return -1; 144 } 145 146 Status File::Read(void *dst, size_t &num_bytes, off_t &offset) { 147 return std::error_code(ENOTSUP, std::system_category()); 148 } 149 150 Status File::Write(const void *src, size_t &num_bytes, off_t &offset) { 151 return std::error_code(ENOTSUP, std::system_category()); 152 } 153 154 Status File::Flush() { return Status(); } 155 156 Status File::Sync() { return Flush(); } 157 158 void File::CalculateInteractiveAndTerminal() { 159 const int fd = GetDescriptor(); 160 if (!DescriptorIsValid(fd)) { 161 m_is_interactive = eLazyBoolNo; 162 m_is_real_terminal = eLazyBoolNo; 163 m_supports_colors = eLazyBoolNo; 164 return; 165 } 166 m_is_interactive = eLazyBoolNo; 167 m_is_real_terminal = eLazyBoolNo; 168 #if defined(_WIN32) 169 if (_isatty(fd)) { 170 m_is_interactive = eLazyBoolYes; 171 m_is_real_terminal = eLazyBoolYes; 172 #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) 173 m_supports_colors = eLazyBoolYes; 174 #endif 175 } 176 #else 177 if (isatty(fd)) { 178 m_is_interactive = eLazyBoolYes; 179 struct winsize window_size; 180 if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) { 181 if (window_size.ws_col > 0) { 182 m_is_real_terminal = eLazyBoolYes; 183 if (llvm::sys::Process::FileDescriptorHasColors(fd)) 184 m_supports_colors = eLazyBoolYes; 185 } 186 } 187 } 188 #endif 189 } 190 191 bool File::GetIsInteractive() { 192 if (m_is_interactive == eLazyBoolCalculate) 193 CalculateInteractiveAndTerminal(); 194 return m_is_interactive == eLazyBoolYes; 195 } 196 197 bool File::GetIsRealTerminal() { 198 if (m_is_real_terminal == eLazyBoolCalculate) 199 CalculateInteractiveAndTerminal(); 200 return m_is_real_terminal == eLazyBoolYes; 201 } 202 203 bool File::GetIsTerminalWithColors() { 204 if (m_supports_colors == eLazyBoolCalculate) 205 CalculateInteractiveAndTerminal(); 206 return m_supports_colors == eLazyBoolYes; 207 } 208 209 size_t File::Printf(const char *format, ...) { 210 va_list args; 211 va_start(args, format); 212 size_t result = PrintfVarArg(format, args); 213 va_end(args); 214 return result; 215 } 216 217 size_t File::PrintfVarArg(const char *format, va_list args) { 218 size_t result = 0; 219 char *s = nullptr; 220 result = vasprintf(&s, format, args); 221 if (s != nullptr) { 222 if (result > 0) { 223 size_t s_len = result; 224 Write(s, s_len); 225 result = s_len; 226 } 227 free(s); 228 } 229 return result; 230 } 231 232 Expected<File::OpenOptions> File::GetOptions() const { 233 return llvm::createStringError( 234 llvm::inconvertibleErrorCode(), 235 "GetOptions() not implemented for this File class"); 236 } 237 238 uint32_t File::GetPermissions(Status &error) const { 239 int fd = GetDescriptor(); 240 if (!DescriptorIsValid(fd)) { 241 error = std::error_code(ENOTSUP, std::system_category()); 242 return 0; 243 } 244 struct stat file_stats; 245 if (::fstat(fd, &file_stats) == -1) { 246 error.SetErrorToErrno(); 247 return 0; 248 } 249 error.Clear(); 250 return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 251 } 252 253 Expected<File::OpenOptions> NativeFile::GetOptions() const { return m_options; } 254 255 int NativeFile::GetDescriptor() const { 256 if (DescriptorIsValid()) 257 return m_descriptor; 258 259 // Don't open the file descriptor if we don't need to, just get it from the 260 // stream if we have one. 261 if (StreamIsValid()) { 262 #if defined(_WIN32) 263 return _fileno(m_stream); 264 #else 265 return fileno(m_stream); 266 #endif 267 } 268 269 // Invalid descriptor and invalid stream, return invalid descriptor. 270 return kInvalidDescriptor; 271 } 272 273 IOObject::WaitableHandle NativeFile::GetWaitableHandle() { 274 return GetDescriptor(); 275 } 276 277 FILE *NativeFile::GetStream() { 278 if (!StreamIsValid()) { 279 if (DescriptorIsValid()) { 280 auto mode = GetStreamOpenModeFromOptions(m_options); 281 if (!mode) 282 llvm::consumeError(mode.takeError()); 283 else { 284 if (!m_own_descriptor) { 285 // We must duplicate the file descriptor if we don't own it because when you 286 // call fdopen, the stream will own the fd 287 #ifdef _WIN32 288 m_descriptor = ::_dup(GetDescriptor()); 289 #else 290 m_descriptor = dup(GetDescriptor()); 291 #endif 292 m_own_descriptor = true; 293 } 294 295 m_stream = llvm::sys::RetryAfterSignal(nullptr, ::fdopen, m_descriptor, 296 mode.get()); 297 298 // If we got a stream, then we own the stream and should no longer own 299 // the descriptor because fclose() will close it for us 300 301 if (m_stream) { 302 m_own_stream = true; 303 m_own_descriptor = false; 304 } 305 } 306 } 307 } 308 return m_stream; 309 } 310 311 Status NativeFile::Close() { 312 Status error; 313 if (StreamIsValid()) { 314 if (m_own_stream) { 315 if (::fclose(m_stream) == EOF) 316 error.SetErrorToErrno(); 317 } else { 318 File::OpenOptions rw = 319 m_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly | 320 File::eOpenOptionReadWrite); 321 322 if (rw == eOpenOptionWriteOnly || rw == eOpenOptionReadWrite) { 323 if (::fflush(m_stream) == EOF) 324 error.SetErrorToErrno(); 325 } 326 } 327 } 328 if (DescriptorIsValid() && m_own_descriptor) { 329 if (::close(m_descriptor) != 0) 330 error.SetErrorToErrno(); 331 } 332 m_descriptor = kInvalidDescriptor; 333 m_stream = kInvalidStream; 334 m_options = OpenOptions(0); 335 m_own_stream = false; 336 m_own_descriptor = false; 337 m_is_interactive = eLazyBoolCalculate; 338 m_is_real_terminal = eLazyBoolCalculate; 339 return error; 340 } 341 342 Status NativeFile::GetFileSpec(FileSpec &file_spec) const { 343 Status error; 344 #ifdef F_GETPATH 345 if (IsValid()) { 346 char path[PATH_MAX]; 347 if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1) 348 error.SetErrorToErrno(); 349 else 350 file_spec.SetFile(path, FileSpec::Style::native); 351 } else { 352 error.SetErrorString("invalid file handle"); 353 } 354 #elif defined(__linux__) 355 char proc[64]; 356 char path[PATH_MAX]; 357 if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0) 358 error.SetErrorString("cannot resolve file descriptor"); 359 else { 360 ssize_t len; 361 if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1) 362 error.SetErrorToErrno(); 363 else { 364 path[len] = '\0'; 365 file_spec.SetFile(path, FileSpec::Style::native); 366 } 367 } 368 #else 369 error.SetErrorString( 370 "NativeFile::GetFileSpec is not supported on this platform"); 371 #endif 372 373 if (error.Fail()) 374 file_spec.Clear(); 375 return error; 376 } 377 378 off_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) { 379 off_t result = 0; 380 if (DescriptorIsValid()) { 381 result = ::lseek(m_descriptor, offset, SEEK_SET); 382 383 if (error_ptr) { 384 if (result == -1) 385 error_ptr->SetErrorToErrno(); 386 else 387 error_ptr->Clear(); 388 } 389 } else if (StreamIsValid()) { 390 result = ::fseek(m_stream, offset, SEEK_SET); 391 392 if (error_ptr) { 393 if (result == -1) 394 error_ptr->SetErrorToErrno(); 395 else 396 error_ptr->Clear(); 397 } 398 } else if (error_ptr) { 399 error_ptr->SetErrorString("invalid file handle"); 400 } 401 return result; 402 } 403 404 off_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) { 405 off_t result = -1; 406 if (DescriptorIsValid()) { 407 result = ::lseek(m_descriptor, offset, SEEK_CUR); 408 409 if (error_ptr) { 410 if (result == -1) 411 error_ptr->SetErrorToErrno(); 412 else 413 error_ptr->Clear(); 414 } 415 } else if (StreamIsValid()) { 416 result = ::fseek(m_stream, offset, SEEK_CUR); 417 418 if (error_ptr) { 419 if (result == -1) 420 error_ptr->SetErrorToErrno(); 421 else 422 error_ptr->Clear(); 423 } 424 } else if (error_ptr) { 425 error_ptr->SetErrorString("invalid file handle"); 426 } 427 return result; 428 } 429 430 off_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) { 431 off_t result = -1; 432 if (DescriptorIsValid()) { 433 result = ::lseek(m_descriptor, offset, SEEK_END); 434 435 if (error_ptr) { 436 if (result == -1) 437 error_ptr->SetErrorToErrno(); 438 else 439 error_ptr->Clear(); 440 } 441 } else if (StreamIsValid()) { 442 result = ::fseek(m_stream, offset, SEEK_END); 443 444 if (error_ptr) { 445 if (result == -1) 446 error_ptr->SetErrorToErrno(); 447 else 448 error_ptr->Clear(); 449 } 450 } else if (error_ptr) { 451 error_ptr->SetErrorString("invalid file handle"); 452 } 453 return result; 454 } 455 456 Status NativeFile::Flush() { 457 Status error; 458 if (StreamIsValid()) { 459 if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF) 460 error.SetErrorToErrno(); 461 } else if (!DescriptorIsValid()) { 462 error.SetErrorString("invalid file handle"); 463 } 464 return error; 465 } 466 467 Status NativeFile::Sync() { 468 Status error; 469 if (DescriptorIsValid()) { 470 #ifdef _WIN32 471 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor)); 472 if (err == 0) 473 error.SetErrorToGenericError(); 474 #else 475 if (llvm::sys::RetryAfterSignal(-1, ::fsync, m_descriptor) == -1) 476 error.SetErrorToErrno(); 477 #endif 478 } else { 479 error.SetErrorString("invalid file handle"); 480 } 481 return error; 482 } 483 484 #if defined(__APPLE__) 485 // Darwin kernels only can read/write <= INT_MAX bytes 486 #define MAX_READ_SIZE INT_MAX 487 #define MAX_WRITE_SIZE INT_MAX 488 #endif 489 490 Status NativeFile::Read(void *buf, size_t &num_bytes) { 491 Status error; 492 493 #if defined(MAX_READ_SIZE) 494 if (num_bytes > MAX_READ_SIZE) { 495 uint8_t *p = (uint8_t *)buf; 496 size_t bytes_left = num_bytes; 497 // Init the num_bytes read to zero 498 num_bytes = 0; 499 500 while (bytes_left > 0) { 501 size_t curr_num_bytes; 502 if (bytes_left > MAX_READ_SIZE) 503 curr_num_bytes = MAX_READ_SIZE; 504 else 505 curr_num_bytes = bytes_left; 506 507 error = Read(p + num_bytes, curr_num_bytes); 508 509 // Update how many bytes were read 510 num_bytes += curr_num_bytes; 511 if (bytes_left < curr_num_bytes) 512 bytes_left = 0; 513 else 514 bytes_left -= curr_num_bytes; 515 516 if (error.Fail()) 517 break; 518 } 519 return error; 520 } 521 #endif 522 523 ssize_t bytes_read = -1; 524 if (DescriptorIsValid()) { 525 bytes_read = llvm::sys::RetryAfterSignal(-1, ::read, m_descriptor, buf, num_bytes); 526 if (bytes_read == -1) { 527 error.SetErrorToErrno(); 528 num_bytes = 0; 529 } else 530 num_bytes = bytes_read; 531 } else if (StreamIsValid()) { 532 bytes_read = ::fread(buf, 1, num_bytes, m_stream); 533 534 if (bytes_read == 0) { 535 if (::feof(m_stream)) 536 error.SetErrorString("feof"); 537 else if (::ferror(m_stream)) 538 error.SetErrorString("ferror"); 539 num_bytes = 0; 540 } else 541 num_bytes = bytes_read; 542 } else { 543 num_bytes = 0; 544 error.SetErrorString("invalid file handle"); 545 } 546 return error; 547 } 548 549 Status NativeFile::Write(const void *buf, size_t &num_bytes) { 550 Status error; 551 552 #if defined(MAX_WRITE_SIZE) 553 if (num_bytes > MAX_WRITE_SIZE) { 554 const uint8_t *p = (const uint8_t *)buf; 555 size_t bytes_left = num_bytes; 556 // Init the num_bytes written to zero 557 num_bytes = 0; 558 559 while (bytes_left > 0) { 560 size_t curr_num_bytes; 561 if (bytes_left > MAX_WRITE_SIZE) 562 curr_num_bytes = MAX_WRITE_SIZE; 563 else 564 curr_num_bytes = bytes_left; 565 566 error = Write(p + num_bytes, curr_num_bytes); 567 568 // Update how many bytes were read 569 num_bytes += curr_num_bytes; 570 if (bytes_left < curr_num_bytes) 571 bytes_left = 0; 572 else 573 bytes_left -= curr_num_bytes; 574 575 if (error.Fail()) 576 break; 577 } 578 return error; 579 } 580 #endif 581 582 ssize_t bytes_written = -1; 583 if (DescriptorIsValid()) { 584 bytes_written = 585 llvm::sys::RetryAfterSignal(-1, ::write, m_descriptor, buf, num_bytes); 586 if (bytes_written == -1) { 587 error.SetErrorToErrno(); 588 num_bytes = 0; 589 } else 590 num_bytes = bytes_written; 591 } else if (StreamIsValid()) { 592 bytes_written = ::fwrite(buf, 1, num_bytes, m_stream); 593 594 if (bytes_written == 0) { 595 if (::feof(m_stream)) 596 error.SetErrorString("feof"); 597 else if (::ferror(m_stream)) 598 error.SetErrorString("ferror"); 599 num_bytes = 0; 600 } else 601 num_bytes = bytes_written; 602 603 } else { 604 num_bytes = 0; 605 error.SetErrorString("invalid file handle"); 606 } 607 608 return error; 609 } 610 611 Status NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) { 612 Status error; 613 614 #if defined(MAX_READ_SIZE) 615 if (num_bytes > MAX_READ_SIZE) { 616 uint8_t *p = (uint8_t *)buf; 617 size_t bytes_left = num_bytes; 618 // Init the num_bytes read to zero 619 num_bytes = 0; 620 621 while (bytes_left > 0) { 622 size_t curr_num_bytes; 623 if (bytes_left > MAX_READ_SIZE) 624 curr_num_bytes = MAX_READ_SIZE; 625 else 626 curr_num_bytes = bytes_left; 627 628 error = Read(p + num_bytes, curr_num_bytes, offset); 629 630 // Update how many bytes were read 631 num_bytes += curr_num_bytes; 632 if (bytes_left < curr_num_bytes) 633 bytes_left = 0; 634 else 635 bytes_left -= curr_num_bytes; 636 637 if (error.Fail()) 638 break; 639 } 640 return error; 641 } 642 #endif 643 644 #ifndef _WIN32 645 int fd = GetDescriptor(); 646 if (fd != kInvalidDescriptor) { 647 ssize_t bytes_read = 648 llvm::sys::RetryAfterSignal(-1, ::pread, fd, buf, num_bytes, offset); 649 if (bytes_read < 0) { 650 num_bytes = 0; 651 error.SetErrorToErrno(); 652 } else { 653 offset += bytes_read; 654 num_bytes = bytes_read; 655 } 656 } else { 657 num_bytes = 0; 658 error.SetErrorString("invalid file handle"); 659 } 660 #else 661 std::lock_guard<std::mutex> guard(offset_access_mutex); 662 long cur = ::lseek(m_descriptor, 0, SEEK_CUR); 663 SeekFromStart(offset); 664 error = Read(buf, num_bytes); 665 if (!error.Fail()) 666 SeekFromStart(cur); 667 #endif 668 return error; 669 } 670 671 Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) { 672 Status error; 673 674 #if defined(MAX_WRITE_SIZE) 675 if (num_bytes > MAX_WRITE_SIZE) { 676 const uint8_t *p = (const uint8_t *)buf; 677 size_t bytes_left = num_bytes; 678 // Init the num_bytes written to zero 679 num_bytes = 0; 680 681 while (bytes_left > 0) { 682 size_t curr_num_bytes; 683 if (bytes_left > MAX_WRITE_SIZE) 684 curr_num_bytes = MAX_WRITE_SIZE; 685 else 686 curr_num_bytes = bytes_left; 687 688 error = Write(p + num_bytes, curr_num_bytes, offset); 689 690 // Update how many bytes were read 691 num_bytes += curr_num_bytes; 692 if (bytes_left < curr_num_bytes) 693 bytes_left = 0; 694 else 695 bytes_left -= curr_num_bytes; 696 697 if (error.Fail()) 698 break; 699 } 700 return error; 701 } 702 #endif 703 704 int fd = GetDescriptor(); 705 if (fd != kInvalidDescriptor) { 706 #ifndef _WIN32 707 ssize_t bytes_written = 708 llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset); 709 if (bytes_written < 0) { 710 num_bytes = 0; 711 error.SetErrorToErrno(); 712 } else { 713 offset += bytes_written; 714 num_bytes = bytes_written; 715 } 716 #else 717 std::lock_guard<std::mutex> guard(offset_access_mutex); 718 long cur = ::lseek(m_descriptor, 0, SEEK_CUR); 719 SeekFromStart(offset); 720 error = Write(buf, num_bytes); 721 long after = ::lseek(m_descriptor, 0, SEEK_CUR); 722 723 if (!error.Fail()) 724 SeekFromStart(cur); 725 726 offset = after; 727 #endif 728 } else { 729 num_bytes = 0; 730 error.SetErrorString("invalid file handle"); 731 } 732 return error; 733 } 734 735 size_t NativeFile::PrintfVarArg(const char *format, va_list args) { 736 if (StreamIsValid()) { 737 return ::vfprintf(m_stream, format, args); 738 } else { 739 return File::PrintfVarArg(format, args); 740 } 741 } 742 743 mode_t File::ConvertOpenOptionsForPOSIXOpen(OpenOptions open_options) { 744 mode_t mode = 0; 745 File::OpenOptions rw = 746 open_options & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly | 747 File::eOpenOptionReadWrite); 748 if (rw == eOpenOptionReadWrite) 749 mode |= O_RDWR; 750 else if (rw == eOpenOptionWriteOnly) 751 mode |= O_WRONLY; 752 else if (rw == eOpenOptionReadOnly) 753 mode |= O_RDONLY; 754 755 if (open_options & eOpenOptionAppend) 756 mode |= O_APPEND; 757 758 if (open_options & eOpenOptionTruncate) 759 mode |= O_TRUNC; 760 761 if (open_options & eOpenOptionNonBlocking) 762 mode |= O_NONBLOCK; 763 764 if (open_options & eOpenOptionCanCreateNewOnly) 765 mode |= O_CREAT | O_EXCL; 766 else if (open_options & eOpenOptionCanCreate) 767 mode |= O_CREAT; 768 769 return mode; 770 } 771 772 llvm::Expected<SerialPort::Options> 773 SerialPort::OptionsFromURL(llvm::StringRef urlqs) { 774 SerialPort::Options serial_options; 775 for (llvm::StringRef x : llvm::split(urlqs, '&')) { 776 if (x.consume_front("baud=")) { 777 unsigned int baud_rate; 778 if (!llvm::to_integer(x, baud_rate, 10)) 779 return llvm::createStringError(llvm::inconvertibleErrorCode(), 780 "Invalid baud rate: %s", 781 x.str().c_str()); 782 serial_options.BaudRate = baud_rate; 783 } else if (x.consume_front("parity=")) { 784 serial_options.Parity = 785 llvm::StringSwitch<llvm::Optional<Terminal::Parity>>(x) 786 .Case("no", Terminal::Parity::No) 787 .Case("even", Terminal::Parity::Even) 788 .Case("odd", Terminal::Parity::Odd) 789 .Case("mark", Terminal::Parity::Mark) 790 .Case("space", Terminal::Parity::Space) 791 .Default(llvm::None); 792 if (!serial_options.Parity) 793 return llvm::createStringError( 794 llvm::inconvertibleErrorCode(), 795 "Invalid parity (must be no, even, odd, mark or space): %s", 796 x.str().c_str()); 797 } else if (x.consume_front("parity-check=")) { 798 serial_options.ParityCheck = 799 llvm::StringSwitch<llvm::Optional<Terminal::ParityCheck>>(x) 800 .Case("no", Terminal::ParityCheck::No) 801 .Case("replace", Terminal::ParityCheck::ReplaceWithNUL) 802 .Case("ignore", Terminal::ParityCheck::Ignore) 803 // "mark" mode is not currently supported as it requires special 804 // input processing 805 // .Case("mark", Terminal::ParityCheck::Mark) 806 .Default(llvm::None); 807 if (!serial_options.ParityCheck) 808 return llvm::createStringError( 809 llvm::inconvertibleErrorCode(), 810 "Invalid parity-check (must be no, replace, ignore or mark): %s", 811 x.str().c_str()); 812 } else if (x.consume_front("stop-bits=")) { 813 unsigned int stop_bits; 814 if (!llvm::to_integer(x, stop_bits, 10) || 815 (stop_bits != 1 && stop_bits != 2)) 816 return llvm::createStringError( 817 llvm::inconvertibleErrorCode(), 818 "Invalid stop bit number (must be 1 or 2): %s", x.str().c_str()); 819 serial_options.StopBits = stop_bits; 820 } else 821 return llvm::createStringError(llvm::inconvertibleErrorCode(), 822 "Unknown parameter: %s", x.str().c_str()); 823 } 824 return serial_options; 825 } 826 827 llvm::Expected<std::unique_ptr<SerialPort>> 828 SerialPort::Create(int fd, OpenOptions options, Options serial_options, 829 bool transfer_ownership) { 830 std::unique_ptr<SerialPort> out{ 831 new SerialPort(fd, options, serial_options, transfer_ownership)}; 832 833 if (!out->GetIsInteractive()) 834 return llvm::createStringError(llvm::inconvertibleErrorCode(), 835 "the specified file is not a teletype"); 836 837 Terminal term{fd}; 838 if (llvm::Error error = term.SetRaw()) 839 return std::move(error); 840 if (serial_options.BaudRate) { 841 if (llvm::Error error = 842 term.SetBaudRate(serial_options.BaudRate.getValue())) 843 return std::move(error); 844 } 845 if (serial_options.Parity) { 846 if (llvm::Error error = term.SetParity(serial_options.Parity.getValue())) 847 return std::move(error); 848 } 849 if (serial_options.ParityCheck) { 850 if (llvm::Error error = 851 term.SetParityCheck(serial_options.ParityCheck.getValue())) 852 return std::move(error); 853 } 854 if (serial_options.StopBits) { 855 if (llvm::Error error = 856 term.SetStopBits(serial_options.StopBits.getValue())) 857 return std::move(error); 858 } 859 860 return std::move(out); 861 } 862 863 SerialPort::SerialPort(int fd, OpenOptions options, 864 SerialPort::Options serial_options, 865 bool transfer_ownership) 866 : NativeFile(fd, options, transfer_ownership), m_state(fd) {} 867 868 Status SerialPort::Close() { 869 m_state.Restore(); 870 return NativeFile::Close(); 871 } 872 873 char File::ID = 0; 874 char NativeFile::ID = 0; 875 char SerialPort::ID = 0; 876