diff --git a/libc/Makefile b/libc/Makefile
index b684ea44..d126ef57 100644
--- a/libc/Makefile
+++ b/libc/Makefile
@@ -354,6 +354,8 @@ sys/socket/socket.o \
sys/socket/socketpair.o \
system.o \
sys/time/gettimeofday.o \
+tcgetpgrp.o \
+tcsetpgrp.o \
tfork.o \
time/clock_getres.o \
time/clock_gettime.o \
diff --git a/libc/include/fsmarshall-msg.h b/libc/include/fsmarshall-msg.h
index 427c237a..37626c38 100644
--- a/libc/include/fsmarshall-msg.h
+++ b/libc/include/fsmarshall-msg.h
@@ -324,7 +324,26 @@ struct fsm_req_unref
ino_t ino;
};
-#define FSM_MSG_NUM 40
+#define FSM_REQ_TCSETPGRP 40
+struct fsm_req_tcsetpgrp
+{
+ ino_t ino;
+ pid_t pgid;
+};
+
+#define FSM_REQ_TCGETPGRP 41
+struct fsm_req_tcgetpgrp
+{
+ ino_t ino;
+};
+
+#define FSM_RESP_TCGETPGRP 42
+struct fsm_resp_tcgetpgrp
+{
+ pid_t pgid;
+};
+
+#define FSM_MSG_NUM 43
#if defined(__cplusplus)
} /* extern "C" */
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index d7587b37..a695b262 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -284,8 +284,6 @@ void swab(const void* __restrict, void* __restrict, ssize_t);
int symlink(const char*, const char*);
int symlinkat(const char*, int, const char*);
void sync(void);
-pid_t tcgetpgrp(int);
-int tcsetpgrp(int, pid_t);
int ttyname_r(int, char*, size_t);
#if __POSIX_OBSOLETE <= 200801
@@ -354,6 +352,8 @@ int setpgid(pid_t, pid_t);
int setuid(uid_t);
unsigned sleep(unsigned);
long sysconf(int);
+pid_t tcgetpgrp(int);
+int tcsetpgrp(int, pid_t);
int truncate(const char*, off_t);
int truncateat(int dirfd, const char*, off_t);
char* ttyname(int);
diff --git a/libc/tcgetpgrp.cpp b/libc/tcgetpgrp.cpp
new file mode 100644
index 00000000..47da799b
--- /dev/null
+++ b/libc/tcgetpgrp.cpp
@@ -0,0 +1,34 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2013.
+
+ This file is part of the Sortix C Library.
+
+ The Sortix C Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or (at your
+ option) any later version.
+
+ The Sortix C Library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with the Sortix C Library. If not, see .
+
+ tcgetpgrp.cpp
+ Get the foreground process group of a terminal.
+
+*******************************************************************************/
+
+#include
+
+#include
+
+DEFN_SYSCALL1(pid_t, sys_tcgetpgrp, SYSCALL_TCGETPGRP, int);
+
+extern "C" pid_t tcgetpgrp(int fd)
+{
+ return sys_tcgetpgrp(fd);
+}
diff --git a/libc/tcsetpgrp.cpp b/libc/tcsetpgrp.cpp
new file mode 100644
index 00000000..ad529778
--- /dev/null
+++ b/libc/tcsetpgrp.cpp
@@ -0,0 +1,34 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2013.
+
+ This file is part of the Sortix C Library.
+
+ The Sortix C Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or (at your
+ option) any later version.
+
+ The Sortix C Library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with the Sortix C Library. If not, see .
+
+ tcsetpgrp.cpp
+ set the foreground process group of a terminal.
+
+*******************************************************************************/
+
+#include
+
+#include
+
+DEFN_SYSCALL2(int, sys_tcsetpgrp, SYSCALL_TCSETPGRP, int, pid_t);
+
+extern "C" int tcsetpgrp(int fd, pid_t pgid)
+{
+ return sys_tcsetpgrp(fd, pgid);
+}
diff --git a/sortix/descriptor.cpp b/sortix/descriptor.cpp
index 08ed411f..367b547a 100644
--- a/sortix/descriptor.cpp
+++ b/sortix/descriptor.cpp
@@ -548,6 +548,16 @@ int Descriptor::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
return vnode->tcgetwinsize(ctx, ws);
}
+int Descriptor::tcsetpgrp(ioctx_t* ctx, pid_t pgid)
+{
+ return vnode->tcsetpgrp(ctx, pgid);
+}
+
+pid_t Descriptor::tcgetpgrp(ioctx_t* ctx)
+{
+ return vnode->tcgetpgrp(ctx);
+}
+
int Descriptor::settermmode(ioctx_t* ctx, unsigned mode)
{
return vnode->settermmode(ctx, mode);
diff --git a/sortix/fs/user.cpp b/sortix/fs/user.cpp
index 77347e94..32cec508 100644
--- a/sortix/fs/user.cpp
+++ b/sortix/fs/user.cpp
@@ -213,6 +213,8 @@ public:
const char* filename);
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
+ virtual int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
+ virtual pid_t tcgetpgrp(ioctx_t* ctx);
virtual int settermmode(ioctx_t* ctx, unsigned mode);
virtual int gettermmode(ioctx_t* ctx, unsigned* mode);
virtual int poll(ioctx_t* ctx, PollNode* node);
@@ -1115,6 +1117,38 @@ int Unode::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
return ret;
}
+int Unode::tcsetpgrp(ioctx_t* /*ctx*/, pid_t pgid)
+{
+ Channel* channel = server->Connect();
+ if ( !channel )
+ return -1;
+ int ret = -1;
+ struct fsm_req_tcsetpgrp msg;
+ msg.ino = ino;
+ msg.pgid = pgid;
+ if ( SendMessage(channel, FSM_REQ_TCSETPGRP, &msg, sizeof(msg)) &&
+ RecvMessage(channel, FSM_RESP_SUCCESS, NULL, 0) )
+ ret = 0;
+ channel->KernelClose();
+ return ret;
+}
+
+pid_t Unode::tcgetpgrp(ioctx_t* /*ctx*/)
+{
+ Channel* channel = server->Connect();
+ if ( !channel )
+ return -1;
+ pid_t ret = -1;
+ struct fsm_req_tcgetpgrp msg;
+ struct fsm_resp_tcgetpgrp resp;
+ msg.ino = ino;
+ if ( SendMessage(channel, FSM_REQ_TCGETPGRP, &msg, sizeof(msg)) &&
+ RecvMessage(channel, FSM_RESP_TCGETPGRP, &resp, sizeof(resp)) )
+ ret = resp.pgid;
+ channel->KernelClose();
+ return ret;
+}
+
int Unode::settermmode(ioctx_t* /*ctx*/, unsigned mode)
{
Channel* channel = server->Connect();
diff --git a/sortix/include/sortix/kernel/descriptor.h b/sortix/include/sortix/kernel/descriptor.h
index ef60ed5f..4fc6fa2b 100644
--- a/sortix/include/sortix/kernel/descriptor.h
+++ b/sortix/include/sortix/kernel/descriptor.h
@@ -78,6 +78,8 @@ public:
int symlink(ioctx_t* ctx, const char* oldname, const char* filename);
ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
+ int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
+ pid_t tcgetpgrp(ioctx_t* ctx);
int settermmode(ioctx_t* ctx, unsigned mode);
int gettermmode(ioctx_t* ctx, unsigned* mode);
int poll(ioctx_t* ctx, PollNode* node);
diff --git a/sortix/include/sortix/kernel/inode.h b/sortix/include/sortix/kernel/inode.h
index 09a1296e..e463c28d 100644
--- a/sortix/include/sortix/kernel/inode.h
+++ b/sortix/include/sortix/kernel/inode.h
@@ -87,6 +87,8 @@ public:
const char* filename) = 0;
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz) = 0;
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws) = 0;
+ virtual int tcsetpgrp(ioctx_t* ctx, pid_t pgid) = 0;
+ virtual pid_t tcgetpgrp(ioctx_t* ctx) = 0;
virtual int settermmode(ioctx_t* ctx, unsigned mode) = 0;
virtual int gettermmode(ioctx_t* ctx, unsigned* mode) = 0;
virtual int poll(ioctx_t* ctx, PollNode* node) = 0;
@@ -163,6 +165,8 @@ public:
const char* filename);
virtual ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
+ virtual int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
+ virtual pid_t tcgetpgrp(ioctx_t* ctx);
virtual int settermmode(ioctx_t* ctx, unsigned mode);
virtual int gettermmode(ioctx_t* ctx, unsigned* mode);
virtual int poll(ioctx_t* ctx, PollNode* node);
diff --git a/sortix/include/sortix/kernel/vnode.h b/sortix/include/sortix/kernel/vnode.h
index de586ef2..5c6c98e6 100644
--- a/sortix/include/sortix/kernel/vnode.h
+++ b/sortix/include/sortix/kernel/vnode.h
@@ -75,6 +75,8 @@ public:
ssize_t readlink(ioctx_t* ctx, char* buf, size_t bufsiz);
int fsbind(ioctx_t* ctx, Vnode* node, int flags);
int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
+ int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
+ pid_t tcgetpgrp(ioctx_t* ctx);
int settermmode(ioctx_t* ctx, unsigned mode);
int gettermmode(ioctx_t* ctx, unsigned* mode);
int poll(ioctx_t* ctx, PollNode* node);
diff --git a/sortix/include/sortix/syscallnum.h b/sortix/include/sortix/syscallnum.h
index dd31dfba..fc796650 100644
--- a/sortix/include/sortix/syscallnum.h
+++ b/sortix/include/sortix/syscallnum.h
@@ -135,6 +135,8 @@
#define SYSCALL_MKPARTITION 111
#define SYSCALL_GETPGID 112
#define SYSCALL_SETPGID 113
-#define SYSCALL_MAX_NUM 114 /* index of highest constant + 1 */
+#define SYSCALL_TCGETPGRP 114
+#define SYSCALL_TCSETPGRP 115
+#define SYSCALL_MAX_NUM 116 /* index of highest constant + 1 */
#endif
diff --git a/sortix/inode.cpp b/sortix/inode.cpp
index 33c9149c..09a85cbf 100644
--- a/sortix/inode.cpp
+++ b/sortix/inode.cpp
@@ -265,6 +265,20 @@ int AbstractInode::tcgetwinsize(ioctx_t* /*ctx*/, struct winsize* /*ws*/)
return errno = ENOTTY, -1;
}
+int AbstractInode::tcsetpgrp(ioctx_t* /*ctx*/, pid_t /*pgid*/)
+{
+ if ( inode_type == INODE_TYPE_TTY )
+ return errno = EBADF, -1;
+ return errno = ENOTTY, -1;
+}
+
+pid_t AbstractInode::tcgetpgrp(ioctx_t* /*ctx*/)
+{
+ if ( inode_type == INODE_TYPE_TTY )
+ return errno = EBADF, -1;
+ return errno = ENOTTY, -1;
+}
+
int AbstractInode::settermmode(ioctx_t* /*ctx*/, unsigned /*mode*/)
{
if ( inode_type == INODE_TYPE_TTY )
diff --git a/sortix/io.cpp b/sortix/io.cpp
index 031c5c1a..e3077745 100644
--- a/sortix/io.cpp
+++ b/sortix/io.cpp
@@ -604,6 +604,24 @@ static int sys_tcgetwinsize(int fd, struct winsize* ws)
return desc->tcgetwinsize(&ctx, ws);
}
+static int sys_tcsetpgrp(int fd, pid_t pgid)
+{
+ Ref desc = CurrentProcess()->GetDescriptor(fd);
+ if ( !desc )
+ return -1;
+ ioctx_t ctx; SetupUserIOCtx(&ctx);
+ return desc->tcsetpgrp(&ctx, pgid);
+}
+
+static int sys_tcgetpgrp(int fd)
+{
+ Ref desc = CurrentProcess()->GetDescriptor(fd);
+ if ( !desc )
+ return -1;
+ ioctx_t ctx; SetupUserIOCtx(&ctx);
+ return desc->tcgetpgrp(&ctx);
+}
+
static int sys_renameat_inner(int olddirfd, const char* oldpath,
int newdirfd, const char* newpath)
{
@@ -973,7 +991,9 @@ void Init()
Syscall::Register(SYSCALL_SEND, (void*) sys_send);
Syscall::Register(SYSCALL_SETTERMMODE, (void*) sys_settermmode);
Syscall::Register(SYSCALL_STAT, (void*) sys_stat);
+ Syscall::Register(SYSCALL_TCGETPGRP, (void*) sys_tcgetpgrp);
Syscall::Register(SYSCALL_TCGETWINSIZE, (void*) sys_tcgetwinsize);
+ Syscall::Register(SYSCALL_TCSETPGRP, (void*) sys_tcsetpgrp);
Syscall::Register(SYSCALL_TRUNCATEAT, (void*) sys_truncateat);
Syscall::Register(SYSCALL_TRUNCATE, (void*) sys_truncate);
Syscall::Register(SYSCALL_UNLINKAT, (void*) sys_unlinkat);
diff --git a/sortix/logterminal.cpp b/sortix/logterminal.cpp
index 1226964c..99d015a0 100644
--- a/sortix/logterminal.cpp
+++ b/sortix/logterminal.cpp
@@ -84,6 +84,7 @@ LogTerminal::LogTerminal(dev_t dev, mode_t mode, uid_t owner, gid_t group,
this->datacond = KTHREAD_COND_INITIALIZER;
this->numwaiting = 0;
this->numeofs = 0;
+ this->foreground_pgid = 0;
keyboard->SetOwner(this, NULL);
}
@@ -128,6 +129,27 @@ int LogTerminal::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
return 0;
}
+int LogTerminal::tcsetpgrp(ioctx_t* /*ctx*/, pid_t pgid)
+{
+ ScopedLock lock(&termlock);
+ Process* process = Process::Get(pgid);
+ if ( !pgid || !process )
+ return errno = ESRCH, -1;
+ kthread_mutex_lock(&process->groupchildlock);
+ bool is_process_group = process->group == process;
+ kthread_mutex_unlock(&process->groupchildlock);
+ if ( !is_process_group )
+ return errno = EINVAL, -1;
+ foreground_pgid = pgid;
+ return 0;
+}
+
+pid_t LogTerminal::tcgetpgrp(ioctx_t* /*ctx*/)
+{
+ ScopedLock lock(&termlock);
+ return foreground_pgid = 0;
+}
+
int LogTerminal::sync(ioctx_t* /*ctx*/)
{
return Log::Sync() ? 0 : -1;
@@ -152,10 +174,17 @@ void LogTerminal::ProcessKeystroke(int kbkey)
{
while ( linebuffer.CanBackspace() )
linebuffer.Backspace();
- pid_t pid = Process::HackGetForegroundProcess();
- Process* process = Process::Get(pid);
- if ( process )
- process->DeliverSignal(SIGINT);
+ if ( foreground_pgid )
+ {
+ if ( Process* process = Process::Get(foreground_pgid) )
+ process->DeliverGroupSignal(SIGINT);
+ }
+ else // TODO: Backwards compatibility, delete this.
+ {
+ pid_t pid = Process::HackGetForegroundProcess();
+ if ( Process* process = Process::Get(pid) )
+ process->DeliverSignal(SIGINT);
+ }
return;
}
if ( termmode & TERMMODE_SIGNAL && control && kbkey == KBKEY_D )
diff --git a/sortix/logterminal.h b/sortix/logterminal.h
index 8763ee0d..8abbe6dd 100644
--- a/sortix/logterminal.h
+++ b/sortix/logterminal.h
@@ -45,6 +45,8 @@ public:
virtual ssize_t read(ioctx_t* ctx, uint8_t* buf, size_t count);
virtual ssize_t write(ioctx_t* ctx, const uint8_t* buf, size_t count);
virtual int tcgetwinsize(ioctx_t* ctx, struct winsize* ws);
+ virtual int tcsetpgrp(ioctx_t* ctx, pid_t pgid);
+ virtual pid_t tcgetpgrp(ioctx_t* ctx);
virtual int settermmode(ioctx_t* ctx, unsigned termmode);
virtual int gettermmode(ioctx_t* ctx, unsigned* termmode);
virtual int poll(ioctx_t* ctx, PollNode* node);
@@ -69,6 +71,7 @@ private:
LineBuffer linebuffer;
size_t partiallywritten;
unsigned termmode;
+ pid_t foreground_pgid;
bool control;
};
diff --git a/sortix/vnode.cpp b/sortix/vnode.cpp
index e635e5d7..1f520e99 100644
--- a/sortix/vnode.cpp
+++ b/sortix/vnode.cpp
@@ -224,6 +224,16 @@ int Vnode::tcgetwinsize(ioctx_t* ctx, struct winsize* ws)
return inode->tcgetwinsize(ctx, ws);
}
+int Vnode::tcsetpgrp(ioctx_t* ctx, pid_t pgid)
+{
+ return inode->tcsetpgrp(ctx, pgid);
+}
+
+pid_t Vnode::tcgetpgrp(ioctx_t* ctx)
+{
+ return inode->tcgetpgrp(ctx);
+}
+
int Vnode::settermmode(ioctx_t* ctx, unsigned mode)
{
return inode->settermmode(ctx, mode);