my xfce4 dotfiles
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
3.5 KiB

3 years ago
  1. // Copyright 2019 Roman Perepelitsa.
  2. //
  3. // This file is part of GitStatus.
  4. //
  5. // GitStatus is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // GitStatus is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with GitStatus. If not, see <https://www.gnu.org/licenses/>.
  17. #include "request.h"
  18. #include <fcntl.h>
  19. #include <signal.h>
  20. #include <sys/select.h>
  21. #include <sys/types.h>
  22. #include <unistd.h>
  23. #include <algorithm>
  24. #include <cstdlib>
  25. #include <iostream>
  26. #include "check.h"
  27. #include "logging.h"
  28. #include "print.h"
  29. #include "serialization.h"
  30. namespace gitstatus {
  31. namespace {
  32. Request ParseRequest(const std::string& s) {
  33. Request res;
  34. auto begin = s.begin(), end = s.end(), sep = std::find(begin, end, kFieldSep);
  35. VERIFY(sep != end) << "Malformed request: " << s;
  36. res.id.assign(begin, sep);
  37. begin = sep + 1;
  38. if (*begin == ':') {
  39. res.from_dotgit = true;
  40. ++begin;
  41. }
  42. sep = std::find(begin, end, kFieldSep);
  43. res.dir.assign(begin, sep);
  44. if (sep == end) return res;
  45. begin = sep + 1;
  46. VERIFY(begin + 1 == end && (*begin == '0' || *begin == '1')) << "Malformed request: " << s;
  47. res.diff = *begin == '0';
  48. return res;
  49. }
  50. bool IsLockedFd(int fd) {
  51. CHECK(fd >= 0);
  52. struct flock flock = {};
  53. flock.l_type = F_RDLCK;
  54. flock.l_whence = SEEK_SET;
  55. CHECK(fcntl(fd, F_GETLK, &flock) != -1) << Errno();
  56. return flock.l_type != F_UNLCK;
  57. }
  58. } // namespace
  59. std::ostream& operator<<(std::ostream& strm, const Request& req) {
  60. strm << Print(req.id) << " for " << Print(req.dir);
  61. if (req.from_dotgit) strm << " [from-dotgit]";
  62. if (!req.diff) strm << " [no-diff]";
  63. return strm;
  64. }
  65. RequestReader::RequestReader(int fd, int lock_fd, int parent_pid)
  66. : fd_(fd), lock_fd_(lock_fd), parent_pid_(parent_pid) {
  67. CHECK(fd != lock_fd);
  68. }
  69. bool RequestReader::ReadRequest(Request& req) {
  70. auto eol = std::find(read_.begin(), read_.end(), kMsgSep);
  71. if (eol != read_.end()) {
  72. std::string msg(read_.begin(), eol);
  73. read_.erase(read_.begin(), eol + 1);
  74. req = ParseRequest(msg);
  75. return true;
  76. }
  77. char buf[256];
  78. while (true) {
  79. fd_set fds;
  80. FD_ZERO(&fds);
  81. FD_SET(fd_, &fds);
  82. struct timeval timeout = {.tv_sec = 1};
  83. int n;
  84. CHECK((n = select(fd_ + 1, &fds, NULL, NULL, &timeout)) >= 0) << Errno();
  85. if (n == 0) {
  86. if (lock_fd_ >= 0 && !IsLockedFd(lock_fd_)) {
  87. LOG(INFO) << "Lock on fd " << lock_fd_ << " is gone. Exiting.";
  88. std::exit(0);
  89. }
  90. if (parent_pid_ >= 0 && kill(parent_pid_, 0)) {
  91. LOG(INFO) << "Unable to send signal 0 to " << parent_pid_ << ". Exiting.";
  92. std::exit(0);
  93. }
  94. req = {};
  95. return false;
  96. }
  97. CHECK((n = read(fd_, buf, sizeof(buf))) >= 0) << Errno();
  98. if (n == 0) {
  99. LOG(INFO) << "EOF. Exiting.";
  100. std::exit(0);
  101. }
  102. read_.insert(read_.end(), buf, buf + n);
  103. int eol = std::find(buf, buf + n, kMsgSep) - buf;
  104. if (eol != n) {
  105. std::string msg(read_.begin(), read_.end() - (n - eol));
  106. read_.erase(read_.begin(), read_.begin() + msg.size() + 1);
  107. req = ParseRequest(msg);
  108. return true;
  109. }
  110. }
  111. }
  112. } // namespace gitstatus