Files
haiku-beta6/src/tests/system/consoled/consoled.cpp
T
Axel Dörfler 77b1fd2243 Renamed the tests/kernel/core directory like the main directory tests/system/kernel
and adapted all Jamfiles.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15630 a95241bf-73f2-0310-859d-f6bbb57e9c96
2005-12-21 00:30:29 +00:00

352 lines
7.7 KiB
C++

/*
* Copyright 2004-2005, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Copyright 2002, Travis Geiselbrecht. All rights reserved.
* Distributed under the terms of the NewOS License.
*/
#include <image.h>
#include <OS.h>
#include <ctype.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
//#define USE_INPUT_SERVER
// define this if consoled should use the input_server to
// get to its keyboard input
// be sure to define USE_R5_STYLE_COMM in InputServer.h when USE_INPUT_SERVER is defined
#ifdef USE_INPUT_SERVER
# include <Message.h>
# include <AppDefs.h>
# include <InterfaceDefs.h>
# include <TypeConstants.h>
# include "VTkeymap.h"
#endif
struct console {
int console_fd;
int keyboard_fd;
int tty_master_fd;
int tty_slave_fd;
int tty_num;
thread_id keyboard_reader;
thread_id console_writer;
sem_id wait_sem;
};
struct console gConsole;
static int32
keyboard_reader(void *arg)
{
struct console *con = (struct console *)arg;
#ifdef USE_INPUT_SERVER
area_id appArea;
void *cursorAddr;
sem_id cursorSem = 0; // not initialized?
thread_id isThread;
port_id isAsPort;
port_id isPort;
appArea = create_area("isCursor", &cursorAddr, B_ANY_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK, B_READ_AREA);
int32 arg_c = 1;
char **arg_v = (char **)malloc(sizeof(char *) * (arg_c + 1));
arg_v[0] = strdup("/system/servers/input_server");
arg_v[1] = NULL;
isThread = load_image(arg_c, (const char**)arg_v, (const char **)environ);
free(arg_v[0]);
int32 tmpbuf[2] = {cursorSem, appArea};
int32 code = 0;
send_data(isThread, code, (void *)tmpbuf, sizeof(tmpbuf));
resume_thread(isThread);
setpgid(isThread, 0);
thread_id sender;
code = receive_data(&sender, (void *)tmpbuf, sizeof(tmpbuf));
isAsPort = tmpbuf[0];
isPort = tmpbuf[1];
ssize_t length;
status_t err;
const char *string;
for (;;) {
length = port_buffer_size(isAsPort);
char buffer[length];
err = read_port(isAsPort, &code, buffer, length);
if(err != length) {
if (err > 0)
fprintf(stderr, "consoled: failed to read full packet (read %lu of %lu)\n", err, length);
else
fprintf(stderr, "consoled: read_port error: (0x%lx) %s\n", err, strerror(err));
continue;
}
BMessage event;
if ((err = event.Unflatten(buffer)) < 0) {
fprintf(stderr, "consoled: Unflatten() error: (0x%lx) %s\n", err, strerror(err));
continue;
}
if ((event.what != B_KEY_DOWN)
|| (event.FindString("bytes", &string) != B_OK))
continue;
length = strlen(string);
if (length == 1)
switch (*string) {
case B_LEFT_ARROW:
write(con->tty_master_fd, LEFT_ARROW_KEY_CODE, sizeof(LEFT_ARROW_KEY_CODE));
break;
case B_RIGHT_ARROW:
write(con->tty_master_fd, RIGHT_ARROW_KEY_CODE, sizeof(RIGHT_ARROW_KEY_CODE));
break;
case B_UP_ARROW:
write(con->tty_master_fd, UP_ARROW_KEY_CODE, sizeof(UP_ARROW_KEY_CODE));
break;
case B_DOWN_ARROW:
write(con->tty_master_fd, DOWN_ARROW_KEY_CODE, sizeof(DOWN_ARROW_KEY_CODE));
break;
default:
write(con->tty_master_fd, string, length);
}
else
write(con->tty_master_fd, string, length);
}
#else // USE_INPUT_SERVER
char buffer[1024];
for (;;) {
ssize_t length = read(con->keyboard_fd, buffer, sizeof(buffer));
if (length < 0)
break;
write(con->tty_master_fd, buffer, length);
}
#endif // USE_INPUT_SERVER
release_sem(con->wait_sem);
return 0;
}
static int32
console_writer(void *arg)
{
char buf[1024];
ssize_t len;
ssize_t write_len;
struct console *con = (struct console *)arg;
for (;;) {
len = read(con->tty_master_fd, buf, sizeof(buf));
if (len < 0)
break;
write_len = write(con->console_fd, buf, len);
}
release_sem(con->wait_sem);
return 0;
}
static int
start_console(struct console *con)
{
DIR *dir;
memset(con, 0, sizeof(struct console));
con->wait_sem = create_sem(0, "console wait sem");
if (con->wait_sem < 0)
return -1;
con->console_fd = open("/dev/console", O_WRONLY);
if (con->console_fd < 0)
return -2;
#ifndef USE_INPUT_SERVER
con->keyboard_fd = open("/dev/keyboard", O_RDONLY);
if (con->keyboard_fd < 0)
return -3;
#endif
dir = opendir("/dev/pt");
if (dir != NULL) {
struct dirent *entry;
char name[64];
while ((entry = readdir(dir)) != NULL) {
if (entry->d_name[0] == '.')
continue;
sprintf(name, "/dev/pt/%s", entry->d_name);
con->tty_master_fd = open(name, O_RDWR);
if (con->tty_master_fd >= 0) {
sprintf(name, "/dev/tt/%s", entry->d_name);
con->tty_slave_fd = open(name, O_RDWR);
if (con->tty_slave_fd < 0) {
fprintf(stderr, "Could not open tty!\n");
close(con->tty_master_fd);
} else {
// set default mode
struct termios termios;
struct winsize size;
if (tcgetattr(con->tty_slave_fd, &termios) == 0) {
termios.c_iflag = ICRNL;
termios.c_oflag = OPOST | ONLCR;
termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHONL;
tcsetattr(con->tty_slave_fd, TCSANOW, &termios);
}
if (ioctl(con->console_fd, TIOCGWINSZ, &size, sizeof(struct winsize)) == 0) {
// we got the window size from the console
ioctl(con->tty_slave_fd, TIOCSWINSZ, &size, sizeof(struct winsize));
}
}
break;
}
}
setenv("TTY", name, true);
}
if (con->tty_master_fd < 0 || con->tty_slave_fd < 0)
return -4;
con->keyboard_reader = spawn_thread(&keyboard_reader, "console reader", B_URGENT_DISPLAY_PRIORITY, con);
if (con->keyboard_reader < 0)
return -7;
con->console_writer = spawn_thread(&console_writer, "console writer", B_URGENT_DISPLAY_PRIORITY, con);
if (con->console_writer < 0)
return -8;
resume_thread(con->keyboard_reader);
resume_thread(con->console_writer);
setenv("TERM", "beterm", true);
#ifdef USE_INPUT_SERVER
// wait for the input_server loop so that keyboard input is available
while (find_thread("_input_server_event_loop_") == NULL) {
snooze(100000);
// a tenth of a second
}
#endif
return 0;
}
static pid_t
start_process(int argc, const char **argv, struct console *con)
{
int saved_stdin, saved_stdout, saved_stderr;
pid_t pid;
saved_stdin = dup(0);
saved_stdout = dup(1);
saved_stderr = dup(2);
dup2(con->tty_slave_fd, 0);
dup2(con->tty_slave_fd, 1);
dup2(con->tty_slave_fd, 2);
pid = load_image(argc, argv, (const char **)environ);
resume_thread(pid);
setpgid(pid, 0);
tcsetpgrp(con->tty_slave_fd, pid);
dup2(saved_stdin, 0);
dup2(saved_stdout, 1);
dup2(saved_stderr, 2);
close(saved_stdin);
close(saved_stdout);
close(saved_stderr);
return pid;
}
int
main(int argc, char **argv)
{
int err;
err = start_console(&gConsole);
if (err < 0) {
printf("consoled: error %d starting console\n", err);
return err;
}
// we're a session leader
setsid();
// move our stdin and stdout to the console
dup2(gConsole.tty_slave_fd, 0);
dup2(gConsole.tty_slave_fd, 1);
dup2(gConsole.tty_slave_fd, 2);
if (argc > 1) {
// a command was given: we run it only once
// get the command argument vector
int commandArgc = argc - 1;
const char **commandArgv = new const char*[commandArgc + 1];
for (int i = 0; i < commandArgc; i++)
commandArgv[i] = argv[i + 1];
commandArgv[commandArgc] = NULL;
// start the process
pid_t process;
status_t returnCode;
process = start_process(commandArgc, commandArgv, &gConsole);
wait_for_thread(process, &returnCode);
} else {
// no command given: start a shell in an endless loop
for (;;) {
pid_t shellProcess;
status_t returnCode;
const char *shellArgv[] = { "/bin/sh", "--login", NULL };
shellProcess = start_process(2, shellArgv, &gConsole);
wait_for_thread(shellProcess, &returnCode);
puts("Restart shell");
}
}
acquire_sem(gConsole.wait_sem);
return 0;
}