Coverage Report

Created: 2023-09-30 09:22

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Host/common/PseudoTerminal.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- PseudoTerminal.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/PseudoTerminal.h"
10
#include "lldb/Host/Config.h"
11
#include "lldb/Host/FileSystem.h"
12
#include "llvm/Support/Errc.h"
13
#include "llvm/Support/Errno.h"
14
#include <cassert>
15
#include <climits>
16
#include <cstdio>
17
#include <cstdlib>
18
#include <cstring>
19
#include <mutex>
20
#if defined(TIOCSCTTY)
21
#include <sys/ioctl.h>
22
#endif
23
24
#include "lldb/Host/PosixApi.h"
25
26
#if defined(__APPLE__)
27
#include <Availability.h>
28
#endif
29
30
#if defined(__ANDROID__)
31
int posix_openpt(int flags);
32
#endif
33
34
using namespace lldb_private;
35
36
// PseudoTerminal constructor
37
30.6k
PseudoTerminal::PseudoTerminal() = default;
38
39
// Destructor
40
//
41
// The destructor will close the primary and secondary file descriptors if they
42
// are valid and ownership has not been released using the
43
// ReleasePrimaryFileDescriptor() or the ReleaseSaveFileDescriptor() member
44
// functions.
45
26.5k
PseudoTerminal::~PseudoTerminal() {
46
26.5k
  ClosePrimaryFileDescriptor();
47
26.5k
  CloseSecondaryFileDescriptor();
48
26.5k
}
49
50
// Close the primary file descriptor if it is valid.
51
26.5k
void PseudoTerminal::ClosePrimaryFileDescriptor() {
52
26.5k
  if (m_primary_fd >= 0) {
53
25
    ::close(m_primary_fd);
54
25
    m_primary_fd = invalid_fd;
55
25
  }
56
26.5k
}
57
58
// Close the secondary file descriptor if it is valid.
59
26.5k
void PseudoTerminal::CloseSecondaryFileDescriptor() {
60
26.5k
  if (m_secondary_fd >= 0) {
61
15
    ::close(m_secondary_fd);
62
15
    m_secondary_fd = invalid_fd;
63
15
  }
64
26.5k
}
65
66
2.12k
llvm::Error PseudoTerminal::OpenFirstAvailablePrimary(int oflag) {
67
2.12k
#if LLDB_ENABLE_POSIX
68
  // Open the primary side of a pseudo terminal
69
2.12k
  m_primary_fd = ::posix_openpt(oflag);
70
2.12k
  if (m_primary_fd < 0) {
71
0
    return llvm::errorCodeToError(
72
0
        std::error_code(errno, std::generic_category()));
73
0
  }
74
75
  // Grant access to the secondary pseudo terminal
76
2.12k
  if (::grantpt(m_primary_fd) < 0) {
77
0
    std::error_code EC(errno, std::generic_category());
78
0
    ClosePrimaryFileDescriptor();
79
0
    return llvm::errorCodeToError(EC);
80
0
  }
81
82
  // Clear the lock flag on the secondary pseudo terminal
83
2.12k
  if (::unlockpt(m_primary_fd) < 0) {
84
0
    std::error_code EC(errno, std::generic_category());
85
0
    ClosePrimaryFileDescriptor();
86
0
    return llvm::errorCodeToError(EC);
87
0
  }
88
89
2.12k
  return llvm::Error::success();
90
#else
91
  return llvm::errorCodeToError(llvm::errc::not_supported);
92
#endif
93
2.12k
}
94
95
15
llvm::Error PseudoTerminal::OpenSecondary(int oflag) {
96
15
  CloseSecondaryFileDescriptor();
97
98
15
  std::string name = GetSecondaryName();
99
15
  m_secondary_fd = FileSystem::Instance().Open(name.c_str(), oflag);
100
15
  if (m_secondary_fd >= 0)
101
15
    return llvm::Error::success();
102
103
0
  return llvm::errorCodeToError(
104
0
      std::error_code(errno, std::generic_category()));
105
15
}
106
107
#if !HAVE_PTSNAME_R || defined(__APPLE__)
108
0
static std::string use_ptsname(int fd) {
109
0
  static std::mutex mutex;
110
0
  std::lock_guard<std::mutex> guard(mutex);
111
0
  const char *r = ptsname(fd);
112
0
  assert(r != nullptr);
113
0
  return r;
114
0
}
115
#endif
116
117
2.12k
std::string PseudoTerminal::GetSecondaryName() const {
118
2.12k
  assert(m_primary_fd >= 0);
119
2.12k
#if HAVE_PTSNAME_R
120
2.12k
#if defined(__APPLE__)
121
2.12k
  if (__builtin_available(macos 10.13.4, iOS 11.3, tvOS 11.3, watchOS 4.4, *)) {
122
2.12k
#endif
123
2.12k
    char buf[PATH_MAX];
124
2.12k
    buf[0] = '\0';
125
2.12k
    int r = ptsname_r(m_primary_fd, buf, sizeof(buf));
126
2.12k
    (void)r;
127
2.12k
    assert(r == 0);
128
2.12k
    return buf;
129
2.12k
#if defined(__APPLE__)
130
2.12k
  } else {
131
0
    return use_ptsname(m_primary_fd);
132
0
  }
133
2.12k
#endif
134
#else
135
  return use_ptsname(m_primary_fd);
136
#endif
137
2.12k
}
138
139
0
llvm::Expected<lldb::pid_t> PseudoTerminal::Fork() {
140
0
#if LLDB_ENABLE_POSIX
141
0
  if (llvm::Error Err = OpenFirstAvailablePrimary(O_RDWR | O_CLOEXEC))
142
0
    return std::move(Err);
143
144
0
  pid_t pid = ::fork();
145
0
  if (pid < 0) {
146
0
    return llvm::errorCodeToError(
147
0
        std::error_code(errno, std::generic_category()));
148
0
  }
149
0
  if (pid > 0) {
150
    // Parent process.
151
0
    return pid;
152
0
  }
153
154
  // Child Process
155
0
  ::setsid();
156
157
0
  if (llvm::Error Err = OpenSecondary(O_RDWR))
158
0
    return std::move(Err);
159
160
  // Primary FD should have O_CLOEXEC set, but let's close it just in
161
  // case...
162
0
  ClosePrimaryFileDescriptor();
163
164
#if defined(TIOCSCTTY)
165
  // Acquire the controlling terminal
166
  if (::ioctl(m_secondary_fd, TIOCSCTTY, (char *)0) < 0) {
167
    return llvm::errorCodeToError(
168
        std::error_code(errno, std::generic_category()));
169
  }
170
#endif
171
  // Duplicate all stdio file descriptors to the secondary pseudo terminal
172
0
  for (int fd : {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}) {
173
0
    if (::dup2(m_secondary_fd, fd) != fd) {
174
0
      return llvm::errorCodeToError(
175
0
          std::error_code(errno, std::generic_category()));
176
0
    }
177
0
  }
178
0
#endif
179
0
  return 0;
180
0
}
181
182
// The primary file descriptor accessor. This object retains ownership of the
183
// primary file descriptor when this accessor is used. Use
184
// ReleasePrimaryFileDescriptor() if you wish this object to release ownership
185
// of the primary file descriptor.
186
//
187
// Returns the primary file descriptor, or -1 if the primary file descriptor is
188
// not currently valid.
189
15
int PseudoTerminal::GetPrimaryFileDescriptor() const { return m_primary_fd; }
190
191
// The secondary file descriptor accessor.
192
//
193
// Returns the secondary file descriptor, or -1 if the secondary file descriptor
194
// is not currently valid.
195
14
int PseudoTerminal::GetSecondaryFileDescriptor() const {
196
14
  return m_secondary_fd;
197
14
}
198
199
// Release ownership of the primary pseudo terminal file descriptor without
200
// closing it. The destructor for this class will close the primary file
201
// descriptor if the ownership isn't released using this call and the primary
202
// file descriptor has been opened.
203
2.10k
int PseudoTerminal::ReleasePrimaryFileDescriptor() {
204
  // Release ownership of the primary pseudo terminal file descriptor without
205
  // closing it. (the destructor for this class will close it otherwise!)
206
2.10k
  int fd = m_primary_fd;
207
2.10k
  m_primary_fd = invalid_fd;
208
2.10k
  return fd;
209
2.10k
}
210
211
// Release ownership of the secondary pseudo terminal file descriptor without
212
// closing it. The destructor for this class will close the secondary file
213
// descriptor if the ownership isn't released using this call and the secondary
214
// file descriptor has been opened.
215
0
int PseudoTerminal::ReleaseSecondaryFileDescriptor() {
216
  // Release ownership of the secondary pseudo terminal file descriptor without
217
  // closing it (the destructor for this class will close it otherwise!)
218
0
  int fd = m_secondary_fd;
219
0
  m_secondary_fd = invalid_fd;
220
0
  return fd;
221
0
}