Coverage Report

Created: 2022-01-22 13:19

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