diff --git a/headers/compatibility/bsd/pty.h b/headers/compatibility/bsd/pty.h index dbb7334caa..7fc8066969 100644 --- a/headers/compatibility/bsd/pty.h +++ b/headers/compatibility/bsd/pty.h @@ -1,5 +1,5 @@ /* - * Copyright 2008, Haiku, Inc. All Rights Reserved. + * Copyright 2008-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef _BSD_PTY_H_ @@ -13,6 +13,9 @@ __BEGIN_DECLS extern int openpty(int* master, int* slave, char* name, struct termios* termAttrs, struct winsize* windowSize); +extern int login_pty(int fd); +extern pid_t forkpty(int* master, char* name, + struct termios* termAttrs, struct winsize* windowSize); __END_DECLS diff --git a/headers/posix/termios.h b/headers/posix/termios.h index 59540629e1..d3073759c5 100644 --- a/headers/posix/termios.h +++ b/headers/posix/termios.h @@ -180,6 +180,7 @@ struct termios { #define TCVTIME (TCGETA + 14) /* pass in bigtime_t, old value saved */ #define TIOCGPGRP (TCGETA + 15) /* Gets the process group ID of the TTY device */ #define TIOCSPGRP (TCGETA + 16) /* Sets the process group ID ('pgid' in BeOS) */ +#define TIOCSCTTY (TCGETA + 17) /* Become controlling TTY */ /* Event codes. Returned from TCWAITEVENT */ #define EV_RING 0x0001 diff --git a/src/add-ons/kernel/drivers/tty/tty.cpp b/src/add-ons/kernel/drivers/tty/tty.cpp index 7c4341d480..dabaedc3ff 100644 --- a/src/add-ons/kernel/drivers/tty/tty.cpp +++ b/src/add-ons/kernel/drivers/tty/tty.cpp @@ -1652,6 +1652,24 @@ tty_ioctl(tty_cookie* cookie, uint32 op, void* buffer, size_t length) tty->settings->pgrp_id = groupID; return error; } + + // become controlling TTY + case TIOCSCTTY: + { + TRACE(("tty: become controlling tty\n")); + pid_t processID = getpid(); + pid_t sessionID = getsid(processID); + // Only session leaders can become controlling tty + if (processID != sessionID) + return B_NOT_ALLOWED; + // Check if already controlling tty + if (team_get_controlling_tty() == tty->index) + return B_OK; + tty->settings->session_id = sessionID; + tty->settings->pgrp_id = sessionID; + team_set_controlling_tty(tty->index); + return B_OK; + } // get and set window size diff --git a/src/libs/bsd/pty.cpp b/src/libs/bsd/pty.cpp index 623682f1ad..322b5c5815 100644 --- a/src/libs/bsd/pty.cpp +++ b/src/libs/bsd/pty.cpp @@ -1,5 +1,6 @@ /* * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All rights reserved. + * Copyright 2010, Jérôme Duval, korli@users.berlios.de. All rights reserved. * Distributed under the terms of the MIT License. */ @@ -31,6 +32,8 @@ openpty(int* _master, int* _slave, char* name, struct termios* termAttrs, if (termAttrs != NULL && tcsetattr(master, TCSANOW, termAttrs) != 0 || windowSize != NULL && ioctl(master, TIOCSWINSZ, windowSize, sizeof(winsize)) != 0) { + // TODO we should either close master and slaves and return -1 + // or we do nothing! close(slave); close(master); } @@ -43,3 +46,47 @@ openpty(int* _master, int* _slave, char* name, struct termios* termAttrs, return 0; } + + +int +login_tty(int fd) +{ + setsid(); + + if (ioctl(fd, TIOCSCTTY, NULL) != 0) + return -1; + + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + + close(fd); + return 0; +} + + +pid_t +forkpty(int* _master, char* name, struct termios* termAttrs, + struct winsize* windowSize) +{ + int master, slave; + if (openpty(&master, &slave, name, termAttrs, windowSize) != 0) + return -1; + + int pid = fork(); + if (pid < 0) { + close(master); + close(slave); + return -1; + } + // child + if (pid == 0) { + close(master); + return login_tty(slave); + } + + // parent + close (slave); + *_master = master; + return pid; +} diff --git a/src/tests/libs/bsd/Jamfile b/src/tests/libs/bsd/Jamfile new file mode 100644 index 0000000000..b7806ffc26 --- /dev/null +++ b/src/tests/libs/bsd/Jamfile @@ -0,0 +1,7 @@ +SubDir HAIKU_TOP src tests libs bsd ; + +UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ; + +SimpleTest forkpty_test : forkpty.c : libbsd.so ; + + diff --git a/src/tests/libs/bsd/forkpty.c b/src/tests/libs/bsd/forkpty.c new file mode 100644 index 0000000000..4fb94b68d0 --- /dev/null +++ b/src/tests/libs/bsd/forkpty.c @@ -0,0 +1,47 @@ +/* from http://jwz.livejournal.com/817438.html */ +#include +#include +#include +#include + +static int +do_fork(void) +{ + int fd = -1; + pid_t pid; + + if ((pid = forkpty(&fd, NULL, NULL, NULL)) < 0) + perror("forkpty"); + else if (!pid) + { + printf ("0123456789\n"); + + /* #### Uncommenting this makes it work! */ + /* sleep(20); */ + + exit (0); + } + + return fd; +} + + +int +main (int argc, char **argv) +{ + char s[1024]; + int n; + int fd = do_fork(); + + /* On 10.4, this prints the whole 10 character line, 1 char per second. + On 10.5, it prints 1 character and stops. + */ + do { + n = read (fd, s, 1); + if (n > 0) fprintf (stderr, "%c", *s); + sleep (1); + } while (n > 0); + + return 0; +} +