BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / tty / slave.cpp
blob77c6296efdbce746f7da3e31dca43bc61b9e8c0f
1 /*
2 ** Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 ** Distributed under the terms of the Haiku License.
4 */
7 #include <stdlib.h>
8 #include <string.h>
10 #include <util/AutoLock.h>
12 #include <team.h>
14 #include "tty_private.h"
17 //#define SLAVE_TRACE
18 #ifdef SLAVE_TRACE
19 # define TRACE(x) dprintf x
20 #else
21 # define TRACE(x)
22 #endif
25 struct slave_cookie : tty_cookie {
29 struct tty gSlaveTTYs[kNumTTYs];
32 static status_t
33 slave_open(const char *name, uint32 flags, void **_cookie)
35 // Get the tty index: Opening "/dev/tty" means opening the process'
36 // controlling tty.
37 int32 index = get_tty_index(name);
38 if (strcmp(name, "tty") == 0) {
39 index = team_get_controlling_tty();
40 if (index < 0)
41 return B_NOT_ALLOWED;
42 } else {
43 index = get_tty_index(name);
44 if (index >= (int32)kNumTTYs)
45 return B_ERROR;
48 TRACE(("slave_open: TTY index = %ld (name = %s)\n", index, name));
50 MutexLocker globalLocker(gGlobalTTYLock);
52 // we may only be used if our master has already been opened
53 if (gMasterTTYs[index].open_count == 0)
54 return B_IO_ERROR;
56 bool makeControllingTTY = (flags & O_NOCTTY) == 0;
57 pid_t processID = getpid();
58 pid_t sessionID = getsid(processID);
60 if (gSlaveTTYs[index].open_count == 0) {
61 // We only allow session leaders to open the tty initially.
62 if (makeControllingTTY && processID != sessionID)
63 return B_NOT_ALLOWED;
65 status_t status = tty_open(&gSlaveTTYs[index], NULL);
66 if (status < B_OK) {
67 // initializing TTY failed
68 return status;
70 } else if (makeControllingTTY) {
71 // If already open, we allow only processes from the same session
72 // to open the tty again.
73 pid_t ttySession = gSlaveTTYs[index].settings->session_id;
74 if (ttySession >= 0) {
75 if (ttySession != sessionID)
76 return B_NOT_ALLOWED;
77 makeControllingTTY = false;
78 } else {
79 // The tty is not associated with a session yet. The process needs
80 // to be a session leader.
81 if (makeControllingTTY && processID != sessionID)
82 return B_NOT_ALLOWED;
86 slave_cookie *cookie = (slave_cookie *)malloc(sizeof(struct slave_cookie));
87 if (cookie == NULL) {
88 if (gSlaveTTYs[index].open_count == 0)
89 tty_close(&gSlaveTTYs[index]);
91 return B_NO_MEMORY;
94 status_t status = init_tty_cookie(cookie, &gSlaveTTYs[index],
95 &gMasterTTYs[index], flags);
96 if (status != B_OK) {
97 free(cookie);
99 if (gSlaveTTYs[index].open_count == 0)
100 tty_close(&gSlaveTTYs[index]);
102 return status;
105 if (gSlaveTTYs[index].open_count == 0) {
106 gSlaveTTYs[index].lock = gMasterTTYs[index].lock;
107 gSlaveTTYs[index].settings->session_id = -1;
108 gSlaveTTYs[index].settings->pgrp_id = -1;
111 if (makeControllingTTY) {
112 gSlaveTTYs[index].settings->session_id = sessionID;
113 gSlaveTTYs[index].settings->pgrp_id = sessionID;
114 team_set_controlling_tty(gSlaveTTYs[index].index);
117 add_tty_cookie(cookie);
119 *_cookie = cookie;
121 return B_OK;
125 static status_t
126 slave_close(void *_cookie)
128 slave_cookie *cookie = (slave_cookie *)_cookie;
130 TRACE(("slave_close: cookie %p\n", _cookie));
132 MutexLocker globalLocker(gGlobalTTYLock);
134 // unblock and wait for all blocking operations
135 tty_close_cookie(cookie);
137 return B_OK;
141 static status_t
142 slave_free_cookie(void *_cookie)
144 // The TTY is already closed. We only have to free the cookie.
145 slave_cookie *cookie = (slave_cookie *)_cookie;
147 TRACE(("slave_free_cookie: cookie %p\n", _cookie));
149 MutexLocker globalLocker(gGlobalTTYLock);
150 uninit_tty_cookie(cookie);
151 globalLocker.Unlock();
153 free(cookie);
155 return B_OK;
159 static status_t
160 slave_ioctl(void *_cookie, uint32 op, void *buffer, size_t length)
162 slave_cookie *cookie = (slave_cookie *)_cookie;
164 TRACE(("slave_ioctl: cookie %p, op %lu, buffer %p, length %lu\n", _cookie, op, buffer, length));
166 return tty_ioctl(cookie, op, buffer, length);
170 static status_t
171 slave_read(void *_cookie, off_t offset, void *buffer, size_t *_length)
173 slave_cookie *cookie = (slave_cookie *)_cookie;
175 TRACE(("slave_read: cookie %p, offset %Ld, buffer %p, length %lu\n",
176 _cookie, offset, buffer, *_length));
178 status_t result = tty_input_read(cookie, buffer, _length);
180 TRACE(("slave_read done: cookie %p, result %lx, length %lu\n",
181 _cookie, result, *_length));
183 return result;
187 static status_t
188 slave_write(void *_cookie, off_t offset, const void *buffer, size_t *_length)
190 slave_cookie *cookie = (slave_cookie *)_cookie;
192 TRACE(("slave_write: cookie %p, offset %Ld, buffer %p, length %lu\n",
193 _cookie, offset, buffer, *_length));
195 status_t result = tty_write_to_tty_slave(cookie, buffer, _length);
197 TRACE(("slave_write done: cookie %p, result %lx, length %lu\n",
198 _cookie, result, *_length));
200 return result;
204 static status_t
205 slave_select(void *_cookie, uint8 event, uint32 ref, selectsync *sync)
207 slave_cookie *cookie = (slave_cookie *)_cookie;
209 return tty_select(cookie, event, ref, sync);
213 static status_t
214 slave_deselect(void *_cookie, uint8 event, selectsync *sync)
216 slave_cookie *cookie = (slave_cookie *)_cookie;
218 return tty_deselect(cookie, event, sync);
222 device_hooks gSlaveTTYHooks = {
223 &slave_open,
224 &slave_close,
225 &slave_free_cookie,
226 &slave_ioctl,
227 &slave_read,
228 &slave_write,
229 &slave_select,
230 &slave_deselect,
231 NULL, // read_pages()
232 NULL // write_pages()