** Copyright 2004, Axel DΓΆrfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the Haiku License.
*/
#include <stdlib.h>
#include <string.h>
#include <util/AutoLock.h>
#include <team.h>
#include "tty_private.h"
#ifdef SLAVE_TRACE
# define TRACE(x) dprintf x
#else
# define TRACE(x)
#endif
struct slave_cookie : tty_cookie {
};
struct tty gSlaveTTYs[kNumTTYs];
static status_t
slave_open(const char *name, uint32 flags, void **_cookie)
{
int32 index = get_tty_index(name);
if (strcmp(name, "tty") == 0) {
index = team_get_controlling_tty();
if (index < 0)
return B_NOT_ALLOWED;
} else {
index = get_tty_index(name);
if (index >= (int32)kNumTTYs)
return B_ERROR;
}
TRACE(("slave_open: TTY index = %ld (name = %s)\n", index, name));
MutexLocker globalLocker(gGlobalTTYLock);
if (gMasterTTYs[index].open_count == 0)
return B_IO_ERROR;
bool makeControllingTTY = (flags & O_NOCTTY) == 0;
pid_t processID = getpid();
pid_t sessionID = getsid(processID);
if (gSlaveTTYs[index].open_count == 0) {
if (makeControllingTTY && processID != sessionID)
return B_NOT_ALLOWED;
status_t status = tty_open(&gSlaveTTYs[index], NULL);
if (status < B_OK) {
return status;
}
} else if (makeControllingTTY) {
pid_t ttySession = gSlaveTTYs[index].settings->session_id;
if (ttySession >= 0) {
if (ttySession != sessionID)
return B_NOT_ALLOWED;
makeControllingTTY = false;
} else {
if (makeControllingTTY && processID != sessionID)
return B_NOT_ALLOWED;
}
}
slave_cookie *cookie = (slave_cookie *)malloc(sizeof(struct slave_cookie));
if (cookie == NULL) {
if (gSlaveTTYs[index].open_count == 0)
tty_close(&gSlaveTTYs[index]);
return B_NO_MEMORY;
}
status_t status = init_tty_cookie(cookie, &gSlaveTTYs[index],
&gMasterTTYs[index], flags);
if (status != B_OK) {
free(cookie);
if (gSlaveTTYs[index].open_count == 0)
tty_close(&gSlaveTTYs[index]);
return status;
}
if (gSlaveTTYs[index].open_count == 0) {
gSlaveTTYs[index].lock = gMasterTTYs[index].lock;
gSlaveTTYs[index].settings->session_id = -1;
gSlaveTTYs[index].settings->pgrp_id = -1;
}
if (makeControllingTTY) {
gSlaveTTYs[index].settings->session_id = sessionID;
gSlaveTTYs[index].settings->pgrp_id = sessionID;
team_set_controlling_tty(gSlaveTTYs[index].index);
}
add_tty_cookie(cookie);
*_cookie = cookie;
return B_OK;
}
static status_t
slave_close(void *_cookie)
{
slave_cookie *cookie = (slave_cookie *)_cookie;
TRACE(("slave_close: cookie %p\n", _cookie));
MutexLocker globalLocker(gGlobalTTYLock);
tty_close_cookie(cookie);
return B_OK;
}
static status_t
slave_free_cookie(void *_cookie)
{
slave_cookie *cookie = (slave_cookie *)_cookie;
TRACE(("slave_free_cookie: cookie %p\n", _cookie));
MutexLocker globalLocker(gGlobalTTYLock);
uninit_tty_cookie(cookie);
globalLocker.Unlock();
free(cookie);
return B_OK;
}
static status_t
slave_ioctl(void *_cookie, uint32 op, void *buffer, size_t length)
{
slave_cookie *cookie = (slave_cookie *)_cookie;
TRACE(("slave_ioctl: cookie %p, op %lu, buffer %p, length %lu\n", _cookie, op, buffer, length));
return tty_ioctl(cookie, op, buffer, length);
}
static status_t
slave_read(void *_cookie, off_t offset, void *buffer, size_t *_length)
{
slave_cookie *cookie = (slave_cookie *)_cookie;
TRACE(("slave_read: cookie %p, offset %Ld, buffer %p, length %lu\n",
_cookie, offset, buffer, *_length));
status_t result = tty_input_read(cookie, buffer, _length);
TRACE(("slave_read done: cookie %p, result %lx, length %lu\n",
_cookie, result, *_length));
return result;
}
static status_t
slave_write(void *_cookie, off_t offset, const void *buffer, size_t *_length)
{
slave_cookie *cookie = (slave_cookie *)_cookie;
TRACE(("slave_write: cookie %p, offset %Ld, buffer %p, length %lu\n",
_cookie, offset, buffer, *_length));
status_t result = tty_write_to_tty_slave(cookie, buffer, _length);
TRACE(("slave_write done: cookie %p, result %lx, length %lu\n",
_cookie, result, *_length));
return result;
}
static status_t
slave_select(void *_cookie, uint8 event, uint32 ref, selectsync *sync)
{
slave_cookie *cookie = (slave_cookie *)_cookie;
return tty_select(cookie, event, ref, sync);
}
static status_t
slave_deselect(void *_cookie, uint8 event, selectsync *sync)
{
slave_cookie *cookie = (slave_cookie *)_cookie;
return tty_deselect(cookie, event, sync);
}
device_hooks gSlaveTTYHooks = {
&slave_open,
&slave_close,
&slave_free_cookie,
&slave_ioctl,
&slave_read,
&slave_write,
&slave_select,
&slave_deselect,
NULL,
NULL
};