The Pedigree Project 0.1
Console.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "Console.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/process/Thread.h"
23#include "pedigree/kernel/processor/Processor.h"
24#include "pedigree/kernel/processor/ProcessorInformation.h"
25
26#include "modules/Module.h"
27
28class RequestQueue;
29
30ConsoleManager ConsoleManager::m_Instance;
31
32void ConsoleManager::newConsole(char c, size_t i) {
33 newConsole(c, i, true);
34}
35
36void ConsoleManager::newConsole(char c, size_t i, bool lock) {
37 char a = 'a' + (i % 10);
38 if (i <= 9)
39 a = '0' + i;
40
41 char master[] = {'p', 't', 'y', c, a, 0};
42 char slave[] = {'t', 't', 'y', c, a, 0};
43
44 String masterName(master), slaveName(slave);
45
46 ConsoleMasterFile* pMaster = new ConsoleMasterFile(i, masterName, this);
47 ConsoleSlaveFile* pSlave = new ConsoleSlaveFile(i, slaveName, this);
48
49 pMaster->setOther(pSlave);
50 pSlave->setOther(pMaster);
51
52 {
53 LockGuard<Spinlock> guard(m_Lock, lock);
54 m_Consoles.pushBack(pMaster);
55 m_Consoles.pushBack(pSlave);
56 }
57}
58
59ConsoleManager::ConsoleManager() : m_Consoles(), m_Lock() {
60 // Create all consoles, so we can look them up easily.
61 for (size_t i = 0; i < 16; ++i) {
62 for (char c = 'p'; c <= 'z'; ++c) {
63 newConsole(c, i, false);
64 }
65 for (char c = 'a'; c <= 'e'; ++c) {
66 newConsole(c, i, false);
67 }
68 }
69}
70
71ConsoleManager::~ConsoleManager() {
72 for (auto it : m_Consoles) {
73 delete it;
74 }
75}
76
77ConsoleManager& ConsoleManager::instance() {
78 return m_Instance;
79}
80
81File* ConsoleManager::getConsole(String consoleName) {
82 LockGuard<Spinlock> guard(m_Lock);
83 for (size_t i = 0; i < m_Consoles.count(); i++) {
84 ConsoleFile* pC = m_Consoles[i];
85 if (pC->m_ConsoleName == consoleName) {
86 return pC;
87 }
88 }
89 // Error - not found.
90 return 0;
91}
92
93ConsoleFile* ConsoleManager::getConsoleFile(RequestQueue* pBackend) {
94 return 0;
95}
96
98 LockGuard<Spinlock> guard(m_Lock);
99 if (!isConsole(file))
100 return false;
101
102 ConsoleMasterFile* pConsole = static_cast<ConsoleMasterFile*>(file);
103 if (!pConsole->isMaster())
104 return false;
105
106 if (pConsole->bLocked)
107 return false;
108
109 Process* pProcess = Processor::information().getCurrentThread()->getParent();
110 pConsole->bLocked = true;
111 pConsole->pLocker = pProcess;
112
113 return true;
114}
115
117 LockGuard<Spinlock> guard(m_Lock);
118 if (!isConsole(file))
119 return;
120
121 ConsoleMasterFile* pConsole = static_cast<ConsoleMasterFile*>(file);
122 if (!pConsole->isMaster())
123 return;
124
125 // Make sure we are the owner of the master.
126 // Forked children shouldn't be able to close() and steal a master pty.
127 Process* pProcess = Processor::information().getCurrentThread()->getParent();
128 if (pConsole->pLocker != pProcess)
129 return;
130 pConsole->bLocked = false;
131}
132
133bool ConsoleManager::setPtyLock(File* file, bool locked) {
134 LockGuard<Spinlock> guard(m_Lock);
135 if (!isConsole(file) || !isMasterConsole(file) || !static_cast<ConsoleFile*>(file)->isPtyMaster())
136 return false;
137
138 ConsoleMasterFile* pConsole = static_cast<ConsoleMasterFile*>(file);
139 pConsole->bSlaveLocked = locked;
140 return true;
141}
142
144 LockGuard<Spinlock> guard(m_Lock);
145 if (!isConsole(file) || !static_cast<ConsoleFile*>(file)->isPtySlave())
146 return false;
147
148 ConsoleFile* other = static_cast<ConsoleFile*>(file)->m_pOther;
149 if (!other || !other->isMaster())
150 return false;
151 return static_cast<ConsoleMasterFile*>(other)->bSlaveLocked;
152}
153
154bool ConsoleManager::isConsole(File* file) {
155 return file && file->isConsole();
156}
157
158bool ConsoleManager::isMasterConsole(File* file) {
159 if (!isConsole(file))
160 return false;
161
162 ConsoleFile* pFile = reinterpret_cast<ConsoleFile*>(file);
163 return pFile->isMaster();
164}
165
166void ConsoleManager::setAttributes(File* file, size_t flags) {
167 // \todo Sanity checking of the flags.
168 if (!file)
169 return;
170 ConsoleFile* pFile = reinterpret_cast<ConsoleFile*>(file);
171 pFile->m_Flags = flags;
172}
173
174void ConsoleManager::getAttributes(File* file, size_t* flags) {
175 if (!file || !flags)
176 return;
177 ConsoleFile* pFile = reinterpret_cast<ConsoleFile*>(file);
178 *flags = pFile->m_Flags;
179}
180
181void ConsoleManager::setControlChars(File* file, void* p) {
182 if (!file || !p)
183 return;
184 ConsoleFile* pFile = reinterpret_cast<ConsoleFile*>(file);
185 MemoryCopy(pFile->m_ControlChars, p, MAX_CONTROL_CHAR);
186}
187
188void ConsoleManager::getControlChars(File* file, void* p) {
189 if (!file || !p)
190 return;
191 ConsoleFile* pFile = reinterpret_cast<ConsoleFile*>(file);
192 MemoryCopy(p, pFile->m_ControlChars, MAX_CONTROL_CHAR);
193}
194
195int ConsoleManager::getWindowSize(File* file, unsigned short* rows, unsigned short* cols) {
196 if (!file)
197 return -1;
198 ConsoleFile* pFile = reinterpret_cast<ConsoleFile*>(file);
199 if (!pFile->isMaster()) {
200 if (pFile->m_pOther) {
201 pFile = pFile->m_pOther;
202 }
203 }
204
205 *rows = pFile->m_Rows;
206 *cols = pFile->m_Cols;
207 return 0;
208}
209
210int ConsoleManager::setWindowSize(File* file, unsigned short rows, unsigned short cols) {
211 if (!file)
212 return false;
213 ConsoleFile* pFile = reinterpret_cast<ConsoleFile*>(file);
214 if ((!pFile->isMaster()) && pFile->m_pOther) {
215 // Ignore. Slave cannot change window size.
216 return 0;
217 }
218 pFile->m_Rows = rows;
219 pFile->m_Cols = cols;
220 return 0;
221}
222
223bool ConsoleManager::hasDataAvailable(File* file) {
224 if (!file)
225 return false;
226 ConsoleFile* pFile = reinterpret_cast<ConsoleFile*>(file);
227 return pFile->select(false, 0);
228}
229
230void ConsoleManager::flush(File* file) {}
231
232File* ConsoleManager::getOther(File* file) {
233 if (!file)
234 return 0;
235 ConsoleFile* pFile = reinterpret_cast<ConsoleFile*>(file);
236 if (!pFile->m_pOther) {
237 return file; // some consoles (e.g. physical) don't have others
238 }
239 return pFile->m_pOther;
240}
241
242static bool initConsole() {
243 return true;
244}
245
246static void destroyConsole() {}
247
248MODULE_INFO("console", &initConsole, &destroyConsole, "vfs");
ConsoleFile * m_pOther
Other side of the console.
Definition Console.h:160
virtual int select(bool bWriting, int timeout)
select - check and optionally for a particular state.
bool lockConsole(File *file)
Definition Console.cc:97
bool setPtyLock(File *file, bool locked)
Set the UNIX 98 PTY slave lock associated with a master.
Definition Console.cc:133
void unlockConsole(File *file)
Release a console master locked as above.
Definition Console.cc:116
bool isPtySlaveLocked(File *file)
Returns whether a PTY slave is currently locked.
Definition Console.cc:143
void newConsole(char c, size_t i)
Definition Console.cc:32
bool bLocked
Is this master locked (ie, already opened)?
Definition Console.h:212
bool bSlaveLocked
Whether the corresponding UNIX 98 slave rejects new opens.
Definition Console.h:219
Process * pLocker
Definition Console.h:216
Definition File.h:75
Process * getParent()
Definition Process.h:620
static ProcessorInformation & information()
void pushBack(const T &value)
Definition Vector.h:275
size_t count() const
Definition Vector.h:270