libposix: deep refactor; add sys/posixly command

With these changes, libposix (and newlib) can run MirBSD Korn Shell.
This commit is contained in:
Giacomo Tesio 2017-09-11 01:01:11 +02:00
parent 2f99fb162f
commit 001069aa7b
56 changed files with 4939 additions and 608 deletions

2
cfg/mksh/profile Normal file
View File

@ -0,0 +1,2 @@
export PWD=`cat /dev/wdir`
export HOSTNAME=$SYSNAME

View File

@ -2,6 +2,11 @@
rfork rfork
if( ! test -d /dev/posix ){
sys/posixly -d /tmp/qa-posixly.log -p $PID &
# sys/ctrace -o /tmp/posixly.trace $APID &
}
dir=$1 dir=$1
if(~ $dir '') dir=/qa if(~ $dir '') dir=/qa

View File

@ -74,7 +74,7 @@ main(void)
elapsed = (nsec() - start) / (1000 * 1000); elapsed = (nsec() - start) / (1000 * 1000);
if(verbose) if(verbose)
fprint(2, "rendezvous interrupted, returned %#p, elapsed = %d ms\n", res, elapsed); fprint(2, "rendezvous interrupted, returned %#p, elapsed = %d ms\n", res, elapsed);
if(!awakened(wkup) || elapsed < 900 || elapsed > 1300){ if(!awakened(wkup) || elapsed < 900 || elapsed > 1800){
print("FAIL: rendezvous\n"); print("FAIL: rendezvous\n");
exits("FAIL"); exits("FAIL");
} }
@ -105,7 +105,7 @@ main(void)
elapsed = (nsec() - start) / (1000 * 1000); elapsed = (nsec() - start) / (1000 * 1000);
if(verbose) if(verbose)
print("semacquire(&sem, 1): returned %lld, elapsed = %d ms\n", res, elapsed); print("semacquire(&sem, 1): returned %lld, elapsed = %d ms\n", res, elapsed);
if(!awakened(wkup) || res != -1 || elapsed < 900 || elapsed > 1300){ if(!awakened(wkup) || res != -1 || elapsed < 900 || elapsed > 1800){
print("FAIL: semacquire\n"); print("FAIL: semacquire\n");
exits("FAIL"); exits("FAIL");
} }
@ -113,8 +113,8 @@ main(void)
/* verify that tsemacquire are NOT interrupted */ /* verify that tsemacquire are NOT interrupted */
fprint(2, "verify that tsemacquire are NOT interrupted\n", elapsed); fprint(2, "verify that tsemacquire are NOT interrupted\n", elapsed);
wkup = awake(700);
start = nsec(); start = nsec();
wkup = awake(500);
res = tsemacquire(&sem, 1500); res = tsemacquire(&sem, 1500);
elapsed = (nsec() - start) / (1000 * 1000); elapsed = (nsec() - start) / (1000 * 1000);
if(verbose) if(verbose)
@ -137,7 +137,7 @@ main(void)
elapsed = (nsec() - start) / (1000 * 1000); elapsed = (nsec() - start) / (1000 * 1000);
if(verbose) if(verbose)
fprint(2, "read(fds[0], buf, 1) returned %lld, elapsed = %d ms\n", res, elapsed); fprint(2, "read(fds[0], buf, 1) returned %lld, elapsed = %d ms\n", res, elapsed);
if(!awakened(wkup) || res != -1 || elapsed < 900 || elapsed > 1300){ if(!awakened(wkup) || res != -1 || elapsed < 900 || elapsed > 1800){
print("FAIL: read\n"); print("FAIL: read\n");
exits("FAIL"); exits("FAIL");
} }
@ -155,7 +155,7 @@ main(void)
elapsed = (nsec() - start) / (1000 * 1000); elapsed = (nsec() - start) / (1000 * 1000);
if(verbose) if(verbose)
fprint(2, "writeTillBlock(fds[0]) returned %lld, elapsed = %d ms\n", res, elapsed); fprint(2, "writeTillBlock(fds[0]) returned %lld, elapsed = %d ms\n", res, elapsed);
if(!awakened(wkup) || res >= 256 || elapsed < 900 || elapsed > 1300){ if(!awakened(wkup) || res >= 256 || elapsed < 900 || elapsed > 1800){
print("FAIL: write\n"); print("FAIL: write\n");
exits("FAIL"); exits("FAIL");
} }

View File

@ -208,7 +208,7 @@ main(int argc, char* argv[])
} }
average = average / NPROC / (1000 * 1000); average = average / NPROC / (1000 * 1000);
if(average < 300) /* we asked for 1ms... we are dumb, after all */ if(average < 1000) /* we asked for 1ms... we are dumb, after all */
{ {
print("PASS\n"); print("PASS\n");
exits("PASS"); exits("PASS");

View File

@ -112,7 +112,7 @@ waiter(int index)
if(verbose) if(verbose)
print("reader %d: got the rlock in %lld ms\n", getpid(), (end - start) / (1000*1000)); print("reader %d: got the rlock in %lld ms\n", getpid(), (end - start) / (1000*1000));
runlock(&afterAWhile); runlock(&afterAWhile);
if((end - start) / (1000*1000) > 1500) if((end - start) / (1000*1000) > 2000)
postnote(PNGROUP, getpid(), smprint("fail: reader %d got the rlock after %lld ms", getpid(), (end - start) / (1000*1000))); postnote(PNGROUP, getpid(), smprint("fail: reader %d got the rlock after %lld ms", getpid(), (end - start) / (1000*1000)));
} else { } else {
if(verbose) if(verbose)
@ -127,7 +127,7 @@ waiter(int index)
rwakeup(&rCompleted); rwakeup(&rCompleted);
qunlock(&rl); qunlock(&rl);
return (end - start) / (1000*1000) < 1300 ? nil : "FAIL"; return (end - start) / (1000*1000) < 2000 ? nil : "FAIL";
} }
void void

View File

@ -214,7 +214,7 @@ main(int argc, char* argv[])
} }
average = average / NPROC / (1000 * 1000); average = average / NPROC / (1000 * 1000);
if(average < 300) /* we asked for 1ms... we are dumb, after all */ if(average < 800) /* we asked for 1ms... we are dumb, after all */
{ {
print("PASS\n"); print("PASS\n");
exits("PASS"); exits("PASS");

View File

@ -215,7 +215,7 @@ main(int argc, char* argv[])
} }
average = average / NPROC / (1000 * 1000); average = average / NPROC / (1000 * 1000);
if(average < 500) /* we asked for 1ms... we are dumb, after all */ if(average < 1000) /* we asked for 1ms... we are dumb, after all */
{ {
print("PASS\n"); print("PASS\n");
exits("PASS"); exits("PASS");

View File

@ -210,7 +210,7 @@ main(int argc, char* argv[])
} }
average = average / NPROC / (1000 * 1000); average = average / NPROC / (1000 * 1000);
if(average < 300) /* we asked for 1ms... we are dumb, after all */ if(average < 1000) /* we asked for 1ms... we are dumb, after all */
{ {
print("PASS\n"); print("PASS\n");
exits("PASS"); exits("PASS");

View File

@ -0,0 +1,7 @@
#include <stdio.h>
int main()
{
fprintf(stdout, "hello, stdout\n");
fprintf(stderr, "hello, stderr\n");
return 0;
}

View File

@ -0,0 +1,27 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void
bye(void)
{
printf("That was all, folks\n");
exit(0);
}
int
main(void)
{
// long a;
int i;
// a = sysconf(_SC_ATEXIT_MAX);
// printf("ATEXIT_MAX = %ld\n", a);
i = atexit(bye);
if (i != 0) {
fprintf(stderr, "cannot set exit function\n");
return 1;
}
return 2;
}

44
qa/lib/newlib/041-env.c Normal file
View File

@ -0,0 +1,44 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int
main ()
{
int child, status;
printf("Parent $PATH = %s\n", getenv("PATH"));
printf("Parent $HOME = %s\n", getenv("HOME"));
printf("Parent $USER = %s\n", getenv("USER"));
printf("Parent $IFS = %s\n", getenv("IFS"));
printf("Parent $ROOT = %s\n", getenv("ROOT"));
printf("Parent $TEST = %s\n", getenv("TEST"));
putenv("TEST=value");
printf("Parent putenv(TEST=value); now $TEST = %s\n", getenv("TEST"));
fflush(stdout);
switch(child = fork()){
case 0:
printf("Child $PATH = %s\n", getenv("PATH"));
printf("Child $HOME = %s\n", getenv("HOME"));
printf("Child $USER = %s\n", getenv("USER"));
printf("Child $IFS = %s\n", getenv("IFS"));
printf("Child $ROOT = %s\n", getenv("ROOT"));
printf("Child $TEST = %s\n", getenv("TEST"));
exit(0);
case -1:
printf("FAIL: fork\n");
return 1;
default:
wait(&status);
break;
}
unsetenv("TEST");
printf("Parent unsetenv(TEST); now $TEST = %s\n", getenv("TEST"));
if(status)
printf("FAIL: child returned %d\n", status);
exit(status);
}

View File

@ -0,0 +1,32 @@
#!/cmd/rc
runner=$0
test = `{echo $runner|sed 's/.runner//'}
test_output = /tmp/output-`{basename $test}
if ( test -e $test_output) rm $test_output
$test > $test_output
expected_lines = ('Parent \$PATH = /cmd:.' \
'Parent \$HOME = '^$HOME \
'Parent \$USER = '^$USER \
'Parent \$ROOT = \(null\)' \
'Parent \$TEST = \(null\)' \
'Parent putenv\(TEST=value\); now \$TEST = value' \
'Child \$PATH = /cmd:.' \
'Child \$HOME = '^$HOME \
'Child \$USER = '^$USER \
'Child \$ROOT = \(null\)' \
'Child \$TEST = value' \
'Parent unsetenv\(TEST\); now \$TEST = \(null\)' \
PASS )
for (line in $expected_lines) {
if ( ! cat $test_output | grep $"line > /dev/null ) {
cat $test_output
echo FAIL: can not find line: $line
exit FAIL
}
}
echo PASS
exit PASS

View File

@ -11,43 +11,46 @@ main(int argc, char **argv)
int p[2], ppgrp, opgrp, npgrp; int p[2], ppgrp, opgrp, npgrp;
char c = '?'; char c = '?';
if (pipe(p) != 0) if (pipe(p) != 0){
perror("pipe() error"); perror("pipe() error");
else { exit(EXIT_FAILURE);
ppgrp = getpgrp(); }
printf("parent's pid %d; process group id %d\n", getpid(), ppgrp); ppgrp = getpgrp();
if ((pid = fork()) == 0) { printf("parent's pid %d; process group id %d\n", getpid(), ppgrp);
opgrp = getpgrp(); if ((pid = fork()) == 0) {
printf("child's pid %d; process group id %d\n", getpid(), opgrp); opgrp = getpgrp();
write(p[1], &c, 1); printf("child's pid %d; process group id %d\n", getpid(), opgrp);
setsid(); if(setsid() == -1){
npgrp = getpgrp(); write(p[1], "e", 1);
if(opgrp == npgrp){ perror("FAIL: setsid");
printf("FAIL: setsid did not changed child's process group id\n"); exit(EXIT_FAILURE);
exit(EXIT_FAILURE); }
} write(p[1], &c, 1);
printf("child's process group id is now %d\n", npgrp); npgrp = getpgrp();
sleep(5); if(opgrp == npgrp){
exit(EXIT_SUCCESS); printf("FAIL: setsid did not changed child's process group id\n");
} else { exit(EXIT_FAILURE);
read(p[0], &c, 1); }
sleep(3); printf("child's process group id is now %d\n", npgrp);
if(ppgrp != getpgrp()){ sleep(5);
printf("FAIL: parent's process group id changed from %d to %d\n", ppgrp, getpgrp()); exit(EXIT_SUCCESS);
exit(EXIT_FAILURE); } else {
} read(p[0], &c, 1);
sleep(3);
if(c == 'e')
exit(EXIT_FAILURE);
if(ppgrp != getpgrp()){
printf("FAIL: parent's process group id changed from %d to %d\n", ppgrp, getpgrp());
exit(EXIT_FAILURE);
}
#ifndef WITH_SIGCHLD #ifndef WITH_SIGCHLD
npgrp = getsid(pid); npgrp = getsid(pid);
if(npgrp < 0){ if(npgrp == ppgrp){
printf("FAIL: parent's getsid(%d) failed with errno %d\n", pid, errno); printf("FAIL: parent's getsid(%d) returned old process group id that should be changed\n", pid);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}
if(npgrp == ppgrp){
printf("FAIL: parent's getsid(%d) returned old process group id that should be changed\n", pid);
exit(EXIT_FAILURE);
}
#endif
} }
#endif
exit(EXIT_SUCCESS);
} }
} }

View File

@ -5,7 +5,7 @@ test_output = /tmp/output-`{basename $test}
if ( test -e $test_output) rm $test_output if ( test -e $test_output) rm $test_output
$test $test_output > /dev/null $test > $test_output
if ( cat $test_output | grep 'FAIL' > /dev/null ) { if ( cat $test_output | grep 'FAIL' > /dev/null ) {
cat $test_output cat $test_output
echo FAIL echo FAIL

48
qa/lib/newlib/120-fcntl.c Normal file
View File

@ -0,0 +1,48 @@
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
// see http://www.informit.com/articles/article.aspx?p=99706&seqNum=13
int
main(int argc, char *argv[])
{
int fd, accmode, val;
if (argc != 2)
fd = 0;
else
fd = atoi(argv[1]);
if ( (val = fcntl(fd, F_GETFL, 0)) < 0){
perror("fcntl error for fd");
exit(1);
}
printf("fcntl(%d) returns %d\n", fd, val);
accmode = val & O_ACCMODE;
if (accmode == O_RDONLY)
printf("read only");
else if (accmode == O_WRONLY)
printf("write only");
else if (accmode == O_RDWR)
printf("read write");
else {
perror("unknown access mode");
exit(1);
}
if (val & O_APPEND)
printf(", append");
if (val & O_NONBLOCK)
printf(", nonblocking");
#if !defined(_POSIX_SOURCE) && defined(O_SYNC)
if (val & O_SYNC)
printf(", synchronous writes");
#endif
putchar('\n');
exit(0);
}

82
qa/lib/newlib/121-fcntl.c Normal file
View File

@ -0,0 +1,82 @@
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
void
fail_if_still_open(int fd)
{
if(fd == 0){
printf("atoi failed\n");
exit(2);
}
if(fcntl(fd, F_GETFD) != -1){
printf("fd %d is still open\n", fd);
exit(3);
}
}
int
main(int argc, char *argv[])
{
int sync[2];
int outfd;
int nullfd;
int tmp;
char *eargv[7], *p;
char buf[128];
if(argc == 1){
printf("cat /proc/%d/fd\n", getpid());
pipe(sync);
outfd = dup(1);
nullfd = open("/dev/null", O_WRONLY);
tmp = fcntl(sync[0], F_DUPFD_CLOEXEC, 1);
close(sync[0]);
sync[0] = tmp;
tmp = fcntl(sync[1], F_DUPFD_CLOEXEC, 1);
close(sync[1]);
sync[1] = tmp;
tmp = fcntl(outfd, F_DUPFD_CLOEXEC, 1);
close(outfd);
outfd = tmp;
tmp = fcntl(nullfd, F_DUPFD_CLOEXEC, 1);
close(nullfd);
nullfd = tmp;
eargv[0] = argv[0];
p = buf;
eargv[1] = p;
p += 1+sprintf(p, "%d", sync[0]);
eargv[2] = p;
p += 1+sprintf(p, "%d", sync[1]);
eargv[3] = p;
p += 1+sprintf(p, "%d", outfd);
eargv[4] = p;
p += 1+sprintf(p, "%d", nullfd);
eargv[5] = NULL;
execvp(argv[0], eargv);
printf("execvp returned\n");
exit(100);
} else if(argc != 5){
printf("argc = %d (should be 5)\n", argc);
exit(1);
}
printf("argc = %d; fds: %s %s %s %s\n", argc, argv[1], argv[2], argv[3], argv[4] );
sync[0] = atoi(argv[1]);
sync[1] = atoi(argv[2]);
outfd = atoi(argv[3]);
nullfd = atoi(argv[4]);
fail_if_still_open(sync[0]);
fail_if_still_open(sync[1]);
fail_if_still_open(outfd);
fail_if_still_open(nullfd);
exit(0);
}

View File

@ -58,6 +58,7 @@ main() {
signal(SIGQUIT, sigquit); signal(SIGQUIT, sigquit);
printf("\nChild going to loop...\n\n"); printf("\nChild going to loop...\n\n");
write(p[1], "", 1);
close(p[1]); close(p[1]);
close(p[0]); close(p[0]);
for(;;); /* loop for ever */ for(;;); /* loop for ever */
@ -65,11 +66,11 @@ main() {
else /* parent */ else /* parent */
{ {
signal(SIGCHLD,sigchld); signal(SIGCHLD,sigchld);
close(p[1]); if(read(p[0], &dummy, 1) != 1){
if(read(p[0], &dummy, 1) > 0){ printf("sync read");
printf("sync read received data");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
close(p[1]);
close(p[0]); close(p[0]);
printf("\nPARENT: sending SIGHUP\n\n"); printf("\nPARENT: sending SIGHUP\n\n");
kill(pid,SIGHUP); kill(pid,SIGHUP);

View File

@ -26,6 +26,7 @@ main() {
if (pid == 0) { if (pid == 0) {
printf("\nI am the new child!\n\n"); printf("\nI am the new child!\n\n");
write(p[1], "", 1);
close(p[1]); close(p[1]);
close(p[0]); close(p[0]);
for(;;){ for(;;){
@ -36,11 +37,11 @@ main() {
} }
else /* parent */ else /* parent */
{ {
close(p[1]); if(read(p[0], &dummy, 1) != 1){
if(read(p[0], &dummy, 1) > 0){ printf("sync read");
printf("sync read received data");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
close(p[1]);
close(p[0]); close(p[0]);
printf("\nPARENT: sending SIGINT\n\n"); printf("\nPARENT: sending SIGINT\n\n");
kill(pid,SIGINT); kill(pid,SIGINT);

View File

@ -28,6 +28,7 @@ main() {
if (pid == 0) { if (pid == 0) {
signal(SIGCONT,sigcont); /* set function calls */ signal(SIGCONT,sigcont); /* set function calls */
printf("Child going to loop...\n"); printf("Child going to loop...\n");
write(p[1], "", 1);
close(p[1]); close(p[1]);
close(p[0]); close(p[0]);
for(;;){ for(;;){
@ -38,11 +39,8 @@ main() {
} }
else /* parent */ else /* parent */
{ {
read(p[0], &dummy, 1);
close(p[1]); close(p[1]);
if(read(p[0], &dummy, 1) > 0){
printf("sync read received data");
exit(EXIT_FAILURE);
}
close(p[0]); close(p[0]);
printf("PARENT: sending SIGCONT\n\n"); printf("PARENT: sending SIGCONT\n\n");
kill(pid,SIGCONT); kill(pid,SIGCONT);

View File

@ -22,7 +22,8 @@ void childloop(void)
{ {
signal(SIGCONT,sigcont); /* set function calls */ signal(SIGCONT,sigcont); /* set function calls */
signal(SIGSTOP,sigstop); /* set function calls */ signal(SIGSTOP,sigstop); /* set function calls */
printf("Child going to loop...\n"); printf("Child %d going to loop...\n", getpid());
write(p[1], "", 1);
close(p[1]); close(p[1]);
close(p[0]); close(p[0]);
for(;;){ for(;;){
@ -54,11 +55,8 @@ main() {
} }
else /* parent */ else /* parent */
{ {
read(p[0], &dummy, 1);
close(p[1]); close(p[1]);
if(read(p[0], &dummy, 1) > 0){
printf("sync read received data");
exit(EXIT_FAILURE);
}
close(p[0]); close(p[0]);
sleep(2); sleep(2);
printf("PARENT: sending SIGSTOP\n"); printf("PARENT: sending SIGSTOP\n");

View File

@ -47,6 +47,7 @@ main() {
signal(SIGQUIT, sigquit); signal(SIGQUIT, sigquit);
printf("Child going to loop...\n"); printf("Child going to loop...\n");
write(p[1], "", 1);
close(p[1]); close(p[1]);
close(p[0]); close(p[0]);
for(;;); /* loop for ever */ for(;;); /* loop for ever */
@ -54,11 +55,8 @@ main() {
else /* parent */ else /* parent */
{ {
signal(SIGCHLD,sigchld); signal(SIGCHLD,sigchld);
read(p[0], &dummy, 1);
close(p[1]); close(p[1]);
if(read(p[0], &dummy, 1) > 0){
printf("sync read received data");
exit(EXIT_FAILURE);
}
close(p[0]); close(p[0]);
printf("PARENT: sending SIGHUP\n"); printf("PARENT: sending SIGHUP\n");
kill(pid,SIGHUP); kill(pid,SIGHUP);

View File

@ -0,0 +1,51 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void sigusr1() {
printf("Got SIGUSR1\n");
exit(0);
}
int
main()
{
sigset_t old_set, new_set;
sigemptyset(&old_set);
sigemptyset(&new_set);
signal(SIGUSR1, sigusr1);
if(sigaddset(&new_set, SIGSEGV) == 0)
{
printf("sigaddset successfully added for SIGSEGV\n");
}
sigprocmask(SIG_BLOCK, &new_set, &old_set);
printf("raise(SIGSEGV)\n");
raise(SIGSEGV);
if(sigaddset(&new_set, SIGUSR1) == 0)
{
printf("sigaddset successfully added for SIGUSR1\n");
}
if(sigprocmask(SIG_BLOCK, &new_set, &old_set) == -1)
{
perror("sigprocmask");
}
printf("raise(SIGUSR1)\n");
raise(SIGUSR1);
sigemptyset(&new_set);
sigaddset(&new_set, SIGUSR1);
printf("unblock SIGUSR1 via sigprocmask\n");
if(sigprocmask(SIG_UNBLOCK, &new_set, &old_set) == -1)
{
perror("sigprocmask");
}
return 1;
}

View File

@ -0,0 +1,74 @@
#define _POSIX_SOURCE
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
int SIGUSR1_caught;
int SIGUSR2_caught;
void catcher(int signum) {
switch (signum) {
case SIGUSR1:
++SIGUSR1_caught;
puts("catcher caught SIGUSR1");
if(SIGUSR2_caught){
puts("FAIL: SIGUSR2 already caught");
exit(1);
}
break;
case SIGUSR2:
++SIGUSR2_caught;
puts("catcher caught SIGUSR2");
break;
default:
printf("catcher caught unexpected signal %d\n", signum);
}
}
int
main()
{
sigset_t sigset;
struct sigaction sact;
time_t t;
if (fork() == 0) {
printf("child is %d\n", getpid());
sleep(10);
puts("child is sending SIGUSR2 signal - which should be blocked");
kill(getppid(), SIGUSR2);
sleep(5);
puts("child is sending SIGUSR1 signal - which should be caught");
kill(getppid(), SIGUSR1);
exit(0);
}
sigemptyset(&sact.sa_mask);
sact.sa_flags = 0;
sact.sa_handler = catcher;
if (sigaction(SIGUSR1, &sact, NULL) != 0)
perror("1st sigaction() error");
else if (sigaction(SIGUSR2, &sact, NULL) != 0)
perror("2nd sigaction() error");
else {
sigfillset(&sigset);
sigdelset(&sigset, SIGUSR1);
time(&t);
printf("parent is waiting for child to send SIGUSR1 at %s",
ctime(&t));
if (sigsuspend(&sigset) == -1)
perror("sigsuspend() returned -1 as expected");
time(&t);
printf("sigsuspend is over at %s", ctime(&t));
}
if(SIGUSR1_caught != 1)
printf("SIGUSR1_caught is %d\n", SIGUSR1_caught);
if(SIGUSR2_caught != 1)
printf("SIGUSR2_caught is %d\n", SIGUSR2_caught);
if(SIGUSR1_caught != 1 || SIGUSR2_caught != 1)
exit(2);
exit(0);
}

View File

@ -0,0 +1,69 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void catcher(int sig) {
puts("Got SIGUSR1");
}
int check_pending(int sig, char *signame) {
sigset_t sigset;
if(sigpending(&sigset) != 0){
perror("sigpending() error\n");
exit(1);
}
if(sigismember(&sigset, sig)){
printf("a %s (%d) signal is pending\n", signame, sig);
return 1;
} else {
printf("no %s (%d) signals are pending\n", signame, sig);
return 0;
}
}
int main(int argc, char *argv[]) {
struct sigaction sigact;
sigset_t sigset;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
if(sigaction(SIGUSR1, &sigact, NULL) != 0){
perror("sigaction() error\n");
return 2;
}
printf("Calling sigprocmask to block SIGUSR1...\n");
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
if (sigprocmask(SIG_SETMASK, &sigset, NULL) != 0){
perror("sigprocmask() error\n");
return 3;
}
printf("SIGUSR1 signals are now blocked\n");
kill(getpid(), SIGUSR1);
printf("kill(getpid(), SIGUSR1) DONE\n");
if(!check_pending(SIGUSR1, "SIGUSR1")){
printf("FAIL: SIGUSR1 is not pending despite the mask\n");
return 4;
}
printf("Calling sigprocmask to unblock SIGUSR1...\n");
sigemptyset(&sigset);
sigprocmask(SIG_SETMASK, &sigset, NULL);
printf("SIGUSR1 signals are no longer blocked\n");
if(check_pending(SIGUSR1, "SIGUSR1")){
printf("FAIL: SIGUSR1 is still pending despite the mask\n");
return 4;
}
return 0;
}

View File

@ -0,0 +1,54 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
void catcher(int sig) {
printf("Signal catcher called for signal %d\n", sig);
}
void timestamp(char *str) {
time_t t;
time(&t);
printf("The time %s is %s", str, ctime(&t));
}
int main(int argc, char *argv[]) {
int result = 0;
int err = 0;
struct sigaction sigact;
sigset_t waitset;
siginfo_t info;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
sigaction(SIGALRM, &sigact, NULL);
sigemptyset(&waitset);
sigaddset(&waitset, SIGALRM);
sigprocmask(SIG_BLOCK, &waitset, NULL);
alarm(3);
timestamp("before sigwaitinfo()");
result = sigwaitinfo(&waitset, &info);
err = errno;
timestamp("after sigwaitinfo()");
if(result > 0){
printf("sigwaitinfo() returned for signal %d\n", info.si_signo);
return 0;
}
printf("sigwaitinfo() returned %d; errno = %d\n", result, err);
perror("sigwaitinfo() function failed");
return 1;
}

View File

@ -0,0 +1,58 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
void catcher(int sig) {
printf("Signal catcher called for signal %d\n", sig);
}
void timestamp(char *str) {
time_t t;
time(&t);
printf("The time %s is %s\n", str, ctime(&t));
}
int main(int argc, char *argv[]) {
int result = 0;
int err = 0;
struct sigaction sigact;
sigset_t waitset;
siginfo_t info;
struct timespec timeout;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
sigaction(SIGALRM, &sigact, NULL);
sigemptyset(&waitset);
sigaddset(&waitset, SIGALRM);
sigprocmask(SIG_BLOCK, &waitset, NULL);
timeout.tv_sec = 4; /* Number of seconds to wait */
timeout.tv_nsec = 1000; /* Number of nanoseconds to wait */
alarm(2);
timestamp("before sigtimedwait()");
result = sigtimedwait(&waitset, &info, &timeout);
err = errno;
timestamp("after sigtimedwait()");
if(result > 0){
printf("sigtimedwait() returned for signal %d\n", info.si_signo);
return 0;
}
printf("sigtimedwait() returned %d; errno = %d\n", result, err);
perror("sigtimedwait() function failed");
return 1;
}

View File

@ -0,0 +1,61 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
void catcher(int sig) {
printf("Signal catcher called for signal %d\n", sig);
}
void timestamp(char *str) {
time_t t;
time(&t);
printf("The time %s is %s\n", str, ctime(&t));
}
int main(int argc, char *argv[]) {
int result = 0;
int err = 0;
struct sigaction sigact;
sigset_t waitset;
siginfo_t info;
struct timespec timeout;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
sigaction(SIGALRM, &sigact, NULL);
sigemptyset(&waitset);
sigaddset(&waitset, SIGALRM);
sigprocmask(SIG_BLOCK, &waitset, NULL);
timeout.tv_sec = 1; /* Number of seconds to wait */
timeout.tv_nsec = 1000; /* Number of nanoseconds to wait */
alarm(4);
timestamp("before sigtimedwait()");
result = sigtimedwait(&waitset, &info, &timeout);
err = errno;
timestamp("after sigtimedwait()");
if(result > 0){
printf("sigtimedwait() returned for signal %d\n", info.si_signo);
return 1;
}
printf("sigtimedwait() returned %d; errno = %d\n", result, err);
if(err != EAGAIN){
perror("errno is not EAGAIN");
return 2;
}
return 0;
}

View File

@ -0,0 +1,54 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
void catcher(int sig) {
printf("Signal catcher called for signal %d\n", sig);
}
void timestamp(char *str) {
time_t t;
time(&t);
printf("The time %s is %s", str, ctime(&t));
}
int main(int argc, char *argv[]) {
int result = 0;
int err = 0;
struct sigaction sigact;
sigset_t waitset;
int sig;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
sigaction(SIGALRM, &sigact, NULL);
sigemptyset(&waitset);
sigaddset(&waitset, SIGALRM);
sigprocmask(SIG_BLOCK, &waitset, NULL);
alarm(3);
timestamp("before sigwait()");
result = sigwait(&waitset, &sig);
err = errno;
timestamp("after sigwait()");
if(result == 0){
printf("sigwait() returned for signal %d\n", sig);
return 0;
}
printf("sigwait() returned %d; errno = %d\n", result, err);
perror("sigwait() function failed");
return 1;
}

View File

@ -0,0 +1,88 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <stdlib.h>
void catcher(int sig, siginfo_t *info, void *p) {
printf("Signal catcher called for signal %d from %d\n", sig, info->si_pid);
exit(1);
}
void timestamp(char *str) {
time_t t;
time(&t);
printf("The time %s is %s", str, ctime(&t));
}
void echoSIGUSR1(void){
int result;
struct sigaction sigact;
sigset_t waitset;
siginfo_t info;
union sigval v;
printf("CHILD pid %d\n", getpid());
v.sival_int = 0;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO;
sigact.sa_sigaction = catcher;
sigaction(SIGUSR1, &sigact, NULL);
sigemptyset(&waitset);
sigaddset(&waitset, SIGUSR1);
sigprocmask(SIG_BLOCK, &waitset, NULL);
while(v.sival_int < 5){
result = sigwaitinfo(&waitset, &info);
v.sival_int = 1 + info.si_value.sival_int;
printf("CHILD sigqueue %d to %d\n", v.sival_int, info.si_pid);
sigqueue(info.si_pid, result, v);
}
}
int main(int argc, char *argv[]) {
int result;
struct sigaction sigact;
sigset_t waitset;
siginfo_t info;
union sigval v;
pid_t child;
switch(child = fork()){
case 0:
echoSIGUSR1();
exit(0);
break;
case -1:
exit(1);
break;
default:
break;
}
printf("PARENT pid %d sleep(3)\n", getpid());
sleep(3);
v.sival_int = 0;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO;
sigact.sa_sigaction = catcher;
sigaction(SIGUSR1, &sigact, NULL);
sigemptyset(&waitset);
sigaddset(&waitset, SIGUSR1);
sigprocmask(SIG_BLOCK, &waitset, NULL);
result = SIGUSR1;
do{
printf("PARENT sigqueue %d\n", v.sival_int);
sigqueue(child, result, v);
result = sigwaitinfo(&waitset, &info);
v.sival_int = 1 + info.si_value.sival_int;
} while(v.sival_int < 5);
exit(0);
}

View File

@ -0,0 +1,132 @@
#include <signal.h>
#include <setjmp.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
sigset_t sigset;
sigjmp_buf mark;
int catcherWasCalled;
void catcher(int);
void p(void);
int main(int argc, char *argv[]) {
int result = 0;
int returnCode = 0;
/*
* Block the SIGUSR2 signal. This signal set will be
* saved as part of the environment by the sigsetjmp()
* function and subsequently restored by the siglongjmp()
* function.
*/
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR2);
sigprocmask(SIG_SETMASK, &sigset, NULL);
/* Save the stack environment and the current signal mask */
returnCode = sigsetjmp(mark, 1);
/* Handle the sigsetjmp return code */
switch(returnCode) {
case 0:
printf("sigsetjmp() has been called\n");
/*
* Call function p() which will call the siglongjmp()
* function
*/
p();
printf("control returning here is an error\n");
result=-1;
break;
case -1:
printf("siglongjmp() function was called\n");
/* Retrieve the current signal mask */
sigprocmask(SIG_SETMASK, NULL, &sigset);
/* Verify SIGUSR2 is in sigset */
if(sigismember(&sigset, SIGUSR2)) {
printf("signal mask was restored after siglongjmp()\n");
result=0;
} else {
printf("signal mask was not restored after siglongjmp()\n");
result=-1;
}
break;
default:
printf("this unexpected return code is an error\n");
result=-1;
break;
}
printf("return from main with result %d\n", result);
return result;
}
void p(void) {
struct sigaction sigact;
int error=0;
printf("performing function p()\n");
/* Setup signal handler in case error condition is detected */
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
sigaction(SIGUSR2, &sigact, NULL);
/*
* Delete SIGUSR2 from the signal set that was initialized
* by the main() function. This allows us to demonstrate
* that the original signal set saved by the sigsetjmp() function
* is restored by the siglongjmp() function.
*/
sigdelset(&sigset, SIGUSR2);
sigprocmask(SIG_SETMASK, &sigset, NULL);
/* After some processing an error condition is detected */
error=-1;
/* Call catcher() function if error is detected */
if(error != 0) {
catcherWasCalled = 0;
/* Send SIGUSR2 to handle the error condition */
printf("error condition detected, send SIGUSR2 signal\n");
kill(getpid(), SIGUSR2);
if(catcherWasCalled == 1) {
printf("catcher() function handled the error condition\n");
/*
* Perform a nonlocal "goto" and specify -1 for the
* return value
*/
siglongjmp(mark, -1);
printf("control getting here is an error\n");
exit(3);
}
}
}
void catcher(int signo) {
/*
* Indicate the catcher() function is handling the
* SIGUSR2 signal.
*/
catcherWasCalled = 1;
}

View File

@ -0,0 +1,38 @@
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
sigset_t parent_mask;
int
main()
{
int status;
sigset_t mask;
sigprocmask(SIG_BLOCK, NULL, &parent_mask);
sigaddset(&parent_mask, SIGSEGV);
sigprocmask(SIG_BLOCK, &parent_mask, NULL);
printf("SIGSEGV blocked in parent. Forking...\n");
switch(fork()){
case -1:
exit(1);
case 0:
sigprocmask(SIG_BLOCK, NULL, &mask);
printf("Is SIGSEGV (%llx) a member of %llx?\n", 1ULL<<(SIGSEGV-1), (long long unsigned int)mask);
if(sigismember(&mask, SIGSEGV) != 1){
printf("FAIL: SIGSEGV is not present in child's mask after fork\n");
exit(2);
}
printf("PASS\n");
exit(0);
default:
wait(&status);
status = WEXITSTATUS(status);
exit(status);
}
}

View File

@ -32,22 +32,37 @@
], ],
"SourceFilesCmd": [ "SourceFilesCmd": [
"000-hello.c", "000-hello.c",
"001-hello.c",
"002-atexit.c",
"010-fork.c", "010-fork.c",
"020-waitpid.c", "020-waitpid.c",
"030-pause.c", "030-pause.c",
"031-setjmp.c", "031-setjmp.c",
"040-gettimeofday.c", "040-gettimeofday.c",
"041-env.c",
"050-setsid.c", "050-setsid.c",
"100-files.c", "100-files.c",
"101-files.c", "101-files.c",
"102-files.c", "102-files.c",
"103-files.c", "103-files.c",
"120-fcntl.c",
"121-fcntl.c",
"200-signals.c", "200-signals.c",
"201-signals.c", "201-signals.c",
"202-signals.c", "202-signals.c",
"203-signals.c", "203-signals.c",
"204-signals.c", "204-signals.c",
"205-signals.c" "205-signals.c",
"206-signals.c",
"207-sigsuspend.c",
"208-sigpending.c",
"209-sigwaitinfo.c",
"210-sigtimedwait.c",
"211-sigtimedwait.c",
"212-sigwait.c",
"213-sigqueue.c",
"214-sigsetjmp.c",
"215-sigprocmask.c"
] ]
}, },
"SIGCHLDTests": { "SIGCHLDTests": {
@ -84,20 +99,37 @@
], ],
"SourceFilesCmd": [ "SourceFilesCmd": [
"000-hello.c", "000-hello.c",
"001-hello.c",
"002-atexit.c",
"010-fork.c", "010-fork.c",
"020-waitpid.c", "020-waitpid.c",
"030-pause.c", "030-pause.c",
"031-setjmp.c",
"040-gettimeofday.c", "040-gettimeofday.c",
"041-env.c",
"050-setsid.c",
"100-files.c", "100-files.c",
"101-files.c", "101-files.c",
"102-files.c", "102-files.c",
"103-files.c", "103-files.c",
"120-fcntl.c",
"121-fcntl.c",
"200-signals.c", "200-signals.c",
"201-signals.c", "201-signals.c",
"202-signals.c", "202-signals.c",
"203-signals.c", "203-signals.c",
"204-signals.c", "204-signals.c",
"205-signals.c" "205-signals.c",
"206-signals.c",
"207-sigsuspend.c",
"208-sigpending.c",
"209-sigwaitinfo.c",
"210-sigtimedwait.c",
"211-sigtimedwait.c",
"212-sigwait.c",
"213-sigqueue.c",
"214-sigsetjmp.c",
"215-sigprocmask.c"
] ]
}, },
"NewlibTestsuite": { "NewlibTestsuite": {

View File

@ -27,18 +27,34 @@ qa_exit_translator(int status)
* should return PASS/FAIL * should return PASS/FAIL
*/ */
if(status == 0){ if(status == 0){
jehanne_print("PASS\n");
return "PASS"; return "PASS";
} else { } else {
jehanne_print("FAIL: " __POSIX_EXIT_PREFIX "%d\n", status);
return "FAIL"; return "FAIL";
} }
} }
return nil; return nil;
} }
void
qa_exit_printer(int status, void *_)
{
extern int printf(const char *format, ...);
if(jehanne_getpid() == jehanne_getmainpid()){
/* the QA test may fork, but only the main process
* should return PASS/FAIL
*/
if(status == 0){
printf("PASS\n");
} else {
printf("FAIL: " __POSIX_EXIT_PREFIX "%d\n", status);
}
}
}
void void
__application_newlib_init(void) __application_newlib_init(void)
{ {
extern int on_exit(void (*func)(int, void*), void* arg);
on_exit(qa_exit_printer, nil);
libposix_translate_exit_status(qa_exit_translator); libposix_translate_exit_status(qa_exit_translator);
} }

View File

@ -27,19 +27,35 @@ qa_exit_translator(int status)
* should return PASS/FAIL * should return PASS/FAIL
*/ */
if(status == 0){ if(status == 0){
jehanne_print("PASS\n");
return "PASS"; return "PASS";
} else { } else {
jehanne_print("FAIL: " __POSIX_EXIT_PREFIX "%d\n", status);
return "FAIL"; return "FAIL";
} }
} }
return nil; return nil;
} }
void
qa_exit_printer(int status, void *_)
{
extern int printf(const char *format, ...);
if(jehanne_getpid() == jehanne_getmainpid()){
/* the QA test may fork, but only the main process
* should return PASS/FAIL
*/
if(status == 0){
printf("PASS\n");
} else {
printf("FAIL: " __POSIX_EXIT_PREFIX "%d\n", status);
}
}
}
void void
__application_newlib_init(void) __application_newlib_init(void)
{ {
extern int on_exit(void (*func)(int, void*), void* arg);
on_exit(qa_exit_printer, nil);
libposix_translate_exit_status(qa_exit_translator); libposix_translate_exit_status(qa_exit_translator);
libposix_emulate_SIGCHLD(); libposix_emulate_SIGCHLD();
} }

View File

@ -30,12 +30,18 @@
* #include <u.h> * #include <u.h>
* #include <posix.h> * #include <posix.h>
* *
* Defining _LIBPOSIX_H before the include allow you to just get dirent * Defining _LIBPOSIX_H before the include allow you to just get
* definition. * data structure definition.
*/ */
#ifndef _LIBPOSIX_DIRENT #ifndef _LIBPOSIX_DEF
#define _LIBPOSIX_DIRENT #define _LIBPOSIX_DEF
struct timespec
{
long tv_sec;
long tv_nsec;
};
/* dirent alias of stat(5) message. /* dirent alias of stat(5) message.
* We (ab)use the fact that both 9P and Jehanne are little endian. * We (ab)use the fact that both 9P and Jehanne are little endian.
@ -75,13 +81,7 @@ struct __attribute__((__packed__)) dirent
#define DT_SOCK 12 #define DT_SOCK 12
#define DT_WHT 14 #define DT_WHT 14
#endif /* _LIBPOSIX_DIRENT */ /* getrusage who */
#ifndef _LIBPOSIX_H
#define _LIBPOSIX_H
typedef unsigned long clock_t;
typedef enum PosixRUsages typedef enum PosixRUsages
{ {
PosixRUsageSelf = 0, PosixRUsageSelf = 0,
@ -90,10 +90,170 @@ typedef enum PosixRUsages
PosixRUsageUnknown = -1 PosixRUsageUnknown = -1
} PosixRUsages; } PosixRUsages;
/* errno values */
#define _ERRNO_H // skip the Posix part, we just need the enum
#include <apw/errno.h>
/* signals */
typedef unsigned long PosixSignalMask;
typedef enum PosixSigProcMaskAction
{
PosixSPMSetMask = 0,
PosixSPMBlock = 1,
PosixSPMUnblock = 2
} PosixSigProcMaskAction;
#define PosixNumberOfSignals (sizeof(PosixSignalMask)*7)
typedef enum PosixSignals
{
PosixSIGABRT = 1,
PosixSIGALRM,
PosixSIGBUS,
PosixSIGCHLD,
PosixSIGCONT,
PosixSIGFPE,
PosixSIGHUP,
PosixSIGILL,
PosixSIGINT,
PosixSIGKILL,
PosixSIGPIPE,
PosixSIGQUIT,
PosixSIGSEGV,
PosixSIGSTOP,
PosixSIGTERM,
PosixSIGTSTP,
PosixSIGTTIN,
PosixSIGTTOU,
PosixSIGUSR1,
PosixSIGUSR2,
PosixSIGPOLL,
PosixSIGPROF,
PosixSIGSYS,
PosixSIGTRAP,
PosixSIGURG,
PosixSIGVTALRM,
PosixSIGXCPU,
PosixSIGXFSZ,
/* Optional Signals */
PosixSIGIOT,
PosixSIGEMT,
PosixSIGSTKFLT,
PosixSIGIO,
PosixSIGPWR,
PosixSIGINFO,
PosixSIGLOST,
PosixSIGWINCH,
PosixSIGUNUSED,
PosixSIGRTMIN,
PosixSIGRTMAX = PosixNumberOfSignals
} PosixSignals;
typedef enum PosixSigActionFlags
{
/* supported flags */
PosixSAFSigInfo = 1<<0,
PosixSAFRestart = 1<<1,
PosixSAFNoChildrenStop = 1<<2,
PosixSAFResetHandler = 1<<3,
PosixSAFNoChildrenWait = 1<<4,
/* ignored flags */
PosixSAFNoDefer = 1<<16, /* notes are not reentrant */
PosixSAFOnStack = 1<<17,
PosixSAFDisable = 1<<18
} PosixSigActionFlags;
typedef enum PosixSigInfoCodes
{
PosixSIUser = 1,
PosixSIQueue,
PosixSITimer,
PosixSIAsyncIO,
PosixSIMsgQueued,
PosixSIFaultMapError,
PosixSIFaultAccessError,
PosixSIChildExited,
PosixSIChildKilled,
PosixSIChildDumped,
PosixSIChildTrapped,
PosixSIChildStopped,
PosixSIChildContinued
} PosixSigInfoCodes;
union sigval {
int sival_int; /* Integer signal value */
void* sival_ptr; /* Pointer signal value */
void* _si_addr; /* Address of faulting address */
int _si_status; /* Child exit status */
uintptr_t _sival_raw; /* Raw value */
};
struct sigevent {
int sigev_notify; /* Notification type */
int sigev_signo; /* Signal number */
union sigval sigev_value; /* Signal value */
void (*sigev_notify_function)( union sigval );
/* Notification function */
long *sigev_notify_attributes; /* Notification Attributes */
};
typedef struct {
int si_signo; /* Signal number */
int si_code; /* Cause of the signal */
int si_errno;
int si_pid; /* Pid of sender */
int si_uid; /* Uid of sender */
union sigval si_value; /* Signal value */
} PosixSignalInfo;
#define si_addr si_value._si_addr
#define si_status si_value._si_status
typedef void (*PosixSigHandler)(int);
typedef void (*PosixSigAction)(int, PosixSignalInfo *, void * );
struct sigaction {
int sa_flags; /* Special flags to affect behavior of signal */
PosixSignalMask sa_mask; /* Additional set of signals to be blocked */
/* during execution of signal-catching */
/* function. */
union {
PosixSigHandler _handler; /* SIG_DFL, SIG_IGN, or pointer to a function */
PosixSigAction _sigaction;
} _signal_handlers;
};
#define sa_handler _signal_handlers._handler
#define sa_sigaction _signal_handlers._sigaction
typedef enum PosixFDCmds
{
PosixFDCDupFD = 1,
PosixFDCDupFDCloseOnExec,
PosixFDCGetFD,
PosixFDCSetFD,
PosixFDCGetFL,
PosixFDCSetFL
} PosixFDCmds;
#endif /* _LIBPOSIX_DEF */
#ifndef _LIBPOSIX_H
#define _LIBPOSIX_H
typedef unsigned long clock_t;
#define __POSIX_EXIT_PREFIX "posix error " #define __POSIX_EXIT_PREFIX "posix error "
#define __POSIX_EXIT_SIGNAL_PREFIX "terminated by posix signal " #define __POSIX_EXIT_SIGNAL_PREFIX "terminated by posix signal "
#define __POSIX_SIGNAL_PREFIX "posix: " #define __POSIX_SIGNAL_PREFIX "posix: "
extern unsigned int POSIX_alarm(int *errnop, unsigned int seconds);
extern int POSIX_access(int *errnop, const char *path, int amode); extern int POSIX_access(int *errnop, const char *path, int amode);
extern int POSIX_dup(int *errnop, int fildes); extern int POSIX_dup(int *errnop, int fildes);
extern int POSIX_dup2(int *errnop, int fildes, int fildes2); extern int POSIX_dup2(int *errnop, int fildes, int fildes2);
@ -134,6 +294,8 @@ extern int POSIX_waitpid(int *errnop, int pid, int *status, int options);
extern long POSIX_write(int *errnop, int fd, const void *buf, size_t len); extern long POSIX_write(int *errnop, int fd, const void *buf, size_t len);
extern int POSIX_gettimeofday(int *errnop, void *timeval, void *timezone); extern int POSIX_gettimeofday(int *errnop, void *timeval, void *timezone);
extern char* POSIX_getenv(int *errnop, const char *name); extern char* POSIX_getenv(int *errnop, const char *name);
extern int POSIX_setenv(int *errno, const char *name, const char *value, int overwrite);
extern int POSIX_unsetenv(int *errnop, const char *name);
extern void *POSIX_sbrk(int *errnop, ptrdiff_t incr); extern void *POSIX_sbrk(int *errnop, ptrdiff_t incr);
extern void * POSIX_malloc(int *errnop, size_t size); extern void * POSIX_malloc(int *errnop, size_t size);
extern void *POSIX_realloc(int *errnop, void *ptr, size_t size); extern void *POSIX_realloc(int *errnop, void *ptr, size_t size);
@ -142,6 +304,19 @@ extern void POSIX_free(void *ptr);
extern unsigned int POSIX_sleep(unsigned int seconds); extern unsigned int POSIX_sleep(unsigned int seconds);
extern int POSIX_pipe(int *errnop, int fildes[2]); extern int POSIX_pipe(int *errnop, int fildes[2]);
extern int POSIX_umask(int *errnop, int mask); extern int POSIX_umask(int *errnop, int mask);
extern int POSIX_fcntl(int *errnop, int fd, PosixFDCmds cmd, uintptr_t arg);
extern int POSIX_sigaddset(int *errnop, PosixSignalMask *set, int signo);
extern int POSIX_sigdelset(int *errnop, PosixSignalMask *set, int signo);
extern int POSIX_sigismember(int *errnop, const PosixSignalMask *set, int signo);
extern int POSIX_sigfillset(int *errnop, PosixSignalMask *set);
extern int POSIX_sigemptyset(int *errnop, PosixSignalMask *set);
extern int POSIX_sigprocmask(int *errnop, PosixSigProcMaskAction how, const PosixSignalMask *set, PosixSignalMask *oset);
extern int POSIX_sigpending(int *errnop, PosixSignalMask *set);
extern int POSIX_sigsuspend(int *errnop, const PosixSignalMask *mask);
extern int POSIX_sigaction(int *errnop, int signo, const struct sigaction *act, struct sigaction *old);
extern int POSIX_sigtimedwait(int *errnop, const PosixSignalMask *set, PosixSignalInfo *info, const struct timespec *timeout);
extern int POSIX_sigqueue(int *errnop, int pid, int signo, const union sigval value);
extern int POSIX_getuid(int *errnop); extern int POSIX_getuid(int *errnop);
extern int POSIX_geteuid(int *errnop); extern int POSIX_geteuid(int *errnop);
@ -159,72 +334,26 @@ extern int POSIX_setpgid(int *errnop, int pid, int pgid);
extern int POSIX_getsid(int *errnop, int pid); extern int POSIX_getsid(int *errnop, int pid);
extern int POSIX_setsid(int *errnop); extern int POSIX_setsid(int *errnop);
extern int POSIX_tcgetpgrp(int *errnop, int fd);
extern int POSIX_tcsetpgrp(int *errnop, int fd, int pgrp);
extern int libposix_getdents(int *errnop, int fd, char *buf, int buf_bytes); extern int libposix_getdents(int *errnop, int fd, char *buf, int buf_bytes);
extern PosixError libposix_translate_kernel_errors(const char *msg);
/* Library initialization /* Library initialization
*/ */
#define _ERRNO_H // skip the Posix part, we just need the enum
#include <apw/errno.h>
typedef enum PosixSignals
{
PosixSIGABRT = 1,
PosixSIGALRM,
PosixSIGBUS,
PosixSIGCHLD,
PosixSIGCONT,
PosixSIGFPE,
PosixSIGHUP,
PosixSIGILL,
PosixSIGINT,
PosixSIGKILL,
PosixSIGPIPE,
PosixSIGQUIT,
PosixSIGSEGV,
PosixSIGSTOP,
PosixSIGTERM,
PosixSIGTSTP,
PosixSIGTTIN,
PosixSIGTTOU,
PosixSIGUSR1,
PosixSIGUSR2,
PosixSIGPOLL,
PosixSIGPROF,
PosixSIGSYS,
PosixSIGTRAP,
PosixSIGURG,
PosixSIGVTALRM,
PosixSIGXCPU,
PosixSIGXFSZ,
/* Optional Signals */
PosixSIGIOT,
PosixSIGEMT,
PosixSIGSTKFLT,
PosixSIGIO,
PosixSIGCLD,
PosixSIGPWR,
PosixSIGINFO,
PosixSIGLOST,
PosixSIGWINCH,
PosixSIGUNUSED,
PosixNumberOfSignals
} PosixSignals;
/* Initialize libposix. Should call /* Initialize libposix. Should call
* *
* libposix_define_errno to set the value of each PosixError * libposix_define_errno to set the value of each PosixError
* libposix_define_signal to set the value of each PosixSignal
* libposix_define_at_fdcwd to set the value of AT_FDCWD (for fchmodat) * libposix_define_at_fdcwd to set the value of AT_FDCWD (for fchmodat)
* libposix_translate_error to translate error strings to PosixError * libposix_translate_error to translate error strings to PosixError
* libposix_set_signal_trampoline to dispatch signal received as notes
* libposix_set_stat_reader * libposix_set_stat_reader
* libposix_set_tms_reader * libposix_set_tms_reader
* libposix_set_timeval_reader * libposix_set_timeval_reader
* libposix_set_timezone_reader * libposix_set_timezone_reader
*/ */
typedef void (*PosixInit)(void); typedef void (*PosixInit)(int argc, char *argv[]);
extern void libposix_init(int argc, char *argv[], PosixInit init) __attribute__((noreturn)); extern void libposix_init(int argc, char *argv[], PosixInit init) __attribute__((noreturn));
/* Translate an error string to a PosixError, in the context of the /* Translate an error string to a PosixError, in the context of the
@ -327,23 +456,11 @@ typedef char* (*PosixExitStatusTranslator)(int status);
extern int libposix_translate_exit_status(PosixExitStatusTranslator translator); extern int libposix_translate_exit_status(PosixExitStatusTranslator translator);
/* Dispatch the signal to the registered handlers. /* Execute process disposition (executed when main returns)
*/ */
typedef enum PosixSignalAction typedef void (*PosixProcessDisposer)(int status);
{
SignalCatched = 1,
SignalIgnored,
SignalError,
SignalDefault
} PosixSignalAction;
typedef PosixSignalAction (*PosixSignalTrampoline)(int signal);
extern int libposix_set_signal_trampoline(PosixSignalTrampoline trampoline);
extern int libposix_define_signal(PosixSignals signal, int code);
extern int libposix_define_realtime_signals(int sigrtmin, int sigrtmax);
extern int libposix_on_process_disposition(PosixProcessDisposer dispose);
/* Enable SIGCHLD emulation /* Enable SIGCHLD emulation
*/ */

View File

@ -1,9 +1,13 @@
{ {
"disk": { "SystemTools": {
"Include": [ "Include": [
"../cmd.json" "../cmd.json"
], ],
"Install": "/arch/$ARCH/cmd/sys/", "Install": "/arch/$ARCH/cmd/sys/",
"Oflags": [
"-static",
"-lc"
],
"Projects": [ "Projects": [
"call/" "call/"
], ],

View File

@ -22,11 +22,11 @@
"/sys/src/lib/mp/", "/sys/src/lib/mp/",
"/sys/src/lib/ndb/", "/sys/src/lib/ndb/",
"/sys/src/lib/plumb/", "/sys/src/lib/plumb/",
"/sys/src/lib/posix/",
"/sys/src/lib/regexp/", "/sys/src/lib/regexp/",
"/sys/src/lib/sec/", "/sys/src/lib/sec/",
"/sys/src/lib/stdio/", "/sys/src/lib/stdio/",
"/sys/src/lib/thread/" "/sys/src/lib/thread/",
"/sys/src/lib/posix/"
] ]
} }
} }

View File

@ -1,6 +1,7 @@
{ {
"LibPosix": { "LibPosix": {
"Cflags": [ "Cflags": [
"-DARCH=\"$ARCH\"",
"-fasm", "-fasm",
"-I." "-I."
], ],
@ -12,16 +13,37 @@
"SourceFiles": [ "SourceFiles": [
"environment.c", "environment.c",
"errors.c", "errors.c",
"fcntl.c",
"files.c", "files.c",
"ids.c", "ids.c",
"initlib.c", "initlib.c",
"kill.c",
"links.c", "links.c",
"memory.c", "memory.c",
"others.c", "others.c",
"processes.c", "processes.c",
"sigchlds.c", "sigchlds.c",
"signals.c", "signals.c",
"sigqueue.c",
"sigsets.c",
"sigsuspend.c",
"termios.c",
"timers.c" "timers.c"
] ]
},
"SignalHelper": {
"Include": [
"../../cmd/cmd.json"
],
"Install": "/arch/$ARCH/cmd/sys/",
"Oflags": [
"-static",
"-lposix",
"-l9p2000",
"-lc"
],
"SourceFilesCmd": [
"posixly.c"
]
} }
} }

View File

@ -89,12 +89,96 @@ put_in_list(EnvVar* newenv)
wunlock(&list_lock); wunlock(&list_lock);
} }
char * static int
POSIX_getenv(int *errno, const char *name) write_env_file(const char *name, const char *value, int size)
{
int f;
char buf[MAX_ENVNAME_LEN];
snprint(buf, sizeof(buf), "/env/%s", name);
f = ocreate(buf, OWRITE, 664);
if(f < 0)
return 0;
if(write(f, value, size) < 0){
close(f);
return 0;
}
close(f);
return 1;
}
int
POSIX_setenv(int *errnop, const char *name, const char *value, int overwrite)
{ {
EnvVar* e; EnvVar* e;
if(name == nil || name[0] == 0 || strchr(name, '=') == nil){ if(name == nil || name[0] == 0 || strchr(name, '=') != nil){
*errno = PosixEINVAL; *errnop = PosixEINVAL;
return -1;
}
if(!overwrite && POSIX_getenv(errnop, name) != nil)
return 0;
if(strlen(name) > 127){
*errnop = PosixENOMEM;
return -1;
}
e = malloc(sizeof(EnvVar));
e->next = nil;
e->value = strdup(value); // see free_env
e->name = strdup(name);
if(!write_env_file(name, e->value, strlen(value) + 1)){
free_env(e);
*errnop = PosixENOMEM;
return -1;
}
put_in_list(e);
return 0;
}
int
POSIX_unsetenv(int *errnop, const char *name)
{
EnvVar* e, **o;
char buf[MAX_ENVNAME_LEN];
if(name == nil || name[0] == 0 || strchr(name, '=') != nil){
*errnop = PosixEINVAL;
return -1;
}
if(POSIX_getenv(errnop, name) == nil)
return 0;
e = malloc(sizeof(EnvVar));
wlock(&list_lock);
e = list_start;
o = &list_start;
while(e != nil){
if(strcmp(e->name, name) == 0){
*o = e->next;
free(e);
e = nil; // done
} else {
o = &e->next;
e = *o;
}
}
wunlock(&list_lock);
snprint(buf, sizeof(buf), "/env/%s", name);
remove(buf);
return 0;
}
char *
POSIX_getenv(int *errnop, const char *name)
{
EnvVar* e;
if(name == nil || name[0] == 0 || strchr(name, '=') != nil){
*errnop = PosixEINVAL;
return nil;
}
if(strlen(name) > 127){
*errnop = PosixEINVAL;
return nil; return nil;
} }
@ -110,12 +194,16 @@ POSIX_getenv(int *errno, const char *name)
return e->value; return e->value;
e = malloc(sizeof(EnvVar)); e = malloc(sizeof(EnvVar));
if(e == nil){
*errnop = PosixEINVAL;
return nil;
}
e->next = nil; e->next = nil;
e->value = nil; // see free_env e->value = nil; // see free_env
e->name = strdup(name); e->name = strdup(name);
if(e->name == nil){ if(e->name == nil){
free_env(e); free_env(e);
*errno = PosixENOMEM; *errnop = PosixEINVAL;
return nil; return nil;
} }
e->value = getenv(name); e->value = getenv(name);

View File

@ -132,6 +132,39 @@ get_posix_error(PosixErrorMap *translations, char *err, uintptr_t caller)
return PosixEINVAL; return PosixEINVAL;
} }
PosixError
libposix_translate_kernel_errors(const char *msg)
{
// TODO: autogenerate from /sys/src/sysconf.json
if(nil == msg)
return 0;
if(strncmp("interrupted", msg, 9) == 0)
return PosixEINTR;
if(strncmp("no living children", msg, 18) == 0)
return PosixECHILD;
if(strstr(msg, "file not found") != nil)
return PosixENOENT;
if(strstr(msg, "does not exist") != nil)
return PosixENOENT;
if(strstr(msg, "file already exists") != nil)
return PosixEEXIST;
if(strstr(msg, "file is a directory") != nil)
return PosixEISDIR;
if(strncmp("fd out of range or not open", msg, 27) == 0)
return PosixEBADF;
if(strstr(msg, "not a directory") != nil)
return PosixENOTDIR;
if(strstr(msg, "permission denied") != nil)
return PosixEPERM;
if(strstr(msg, "name too long") != nil)
return PosixENAMETOOLONG;
if(strcmp("i/o error", msg) == 0)
return PosixEIO;
if(strcmp("i/o on hungup channel", msg) == 0)
return PosixEIO;
return 0;
}
int int
__libposix_translate_errstr(uintptr_t caller) __libposix_translate_errstr(uintptr_t caller)
{ {
@ -153,6 +186,8 @@ __libposix_translate_errstr(uintptr_t caller)
perr = get_posix_error(handler->head, err, caller); perr = get_posix_error(handler->head, err, caller);
if(perr == 0) if(perr == 0)
perr = get_posix_error(generic_handlers, err, caller); perr = get_posix_error(generic_handlers, err, caller);
if(perr == 0)
perr = libposix_translate_kernel_errors(err);
ret = __libposix_get_errno(perr); ret = __libposix_get_errno(perr);
sys_errstr(err, ERRMAX); sys_errstr(err, ERRMAX);
return ret; return ret;

159
sys/src/lib/posix/fcntl.c Normal file
View File

@ -0,0 +1,159 @@
/*
* This file is part of Jehanne.
*
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3 of the License.
*
* Jehanne 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 General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
*/
#include <u.h>
#include <lib9.h>
#include <posix.h>
#include "internal.h"
static int
fcntl_dup(int *errnop, int fd, int minfd)
{
int newfd, i;
char buf[128];
int opened[32];
PosixError e;
if(fd < 0 || minfd < 0){
*errnop = __libposix_get_errno(PosixEBADF);
return -1;
}
snprint(buf, sizeof(buf), "/fd/%d", minfd);
if(access(buf, AEXIST) != 0){
if(dup(fd, minfd) < 0){
*errnop = __libposix_get_errno(PosixEBADF);
return -1;
}
return minfd;
}
e = 0;
i = 0;
do
{
newfd = dup(fd, -1);
if(newfd < 0){
e = PosixEINVAL;
break;
}
opened[i++] = newfd;
} while(newfd < minfd && i < nelem(opened));
--i;
if(newfd >= minfd)
--i;
while(i >= 0)
close(opened[i--]);
if(newfd >= minfd)
return newfd;
close(newfd);
if(e == 0)
e = PosixEMFILE;
*errnop = __libposix_get_errno(e);
return -1;
}
static int
file_flags(int *errnop, int fd)
{
int newfd, r, flags;
char buf[128], *cols[3];
snprint(buf, sizeof(buf), "/fd/%dctl", fd);
newfd = open(buf, OREAD);
if(newfd < 0)
goto FailWithEBADF;
r = read(newfd, buf, sizeof(buf));
close(newfd);
if(r < 0)
goto FailWithEBADF;
r = getfields(buf, cols, 3, 1, " ");
if(r < 3)
goto FailWithEBADF;
flags = 0;
if(strchr(cols[1], 'E'))
flags |= OCEXEC;
else if(__libposix_should_close_on_exec(fd))
flags |= OCEXEC;
if(strchr(cols[1], 'r'))
flags |= OREAD;
else if(strchr(cols[1], 'R'))
flags |= OREAD;
if(strchr(cols[1], 'w'))
flags |= OWRITE;
else if(strchr(cols[1], 'W'))
flags |= OWRITE;
return flags;
FailWithEBADF:
*errnop = __libposix_get_errno(PosixEBADF);
return -1;
}
int
POSIX_fcntl(int *errnop, int fd, PosixFDCmds cmd, uintptr_t arg)
{
int tmp;
int flags;
switch(cmd){
case PosixFDCDupFD:
return fcntl_dup(errnop, fd, (int)arg);
case PosixFDCDupFDCloseOnExec:
if((tmp = fcntl_dup(errnop, fd, (int)arg)) < 0)
return -1;
flags = file_flags(errnop, tmp);
if(flags < 0)
return -1;
if((flags&OCEXEC) == 0)
__libposix_set_close_on_exec(tmp, 1);
return tmp;
case PosixFDCGetFD:
flags = file_flags(errnop, fd);
if(flags < 0)
return -1;
return flags & OCEXEC;
case PosixFDCSetFD:
if(arg){
if((file_flags(errnop, fd)&OCEXEC) == 0)
__libposix_set_close_on_exec(fd, 1);
} else {
if((file_flags(errnop, fd)&OCEXEC) != 0)
__libposix_set_close_on_exec(fd, 0);
}
return 0;
case PosixFDCGetFL:
flags = file_flags(errnop, fd);
if(flags < 0)
return -1;
return flags & (~OCEXEC);
case PosixFDCSetFL:
return 0;
break;
}
*errnop = __libposix_get_errno(PosixEINVAL);
return -1;
}

View File

@ -29,6 +29,10 @@ static int __libposix_R_OK;
static int __libposix_W_OK; static int __libposix_W_OK;
static int __libposix_X_OK; static int __libposix_X_OK;
static int *__libposix_coe_fds;
static int __libposix_coe_fds_size;
static int __libposix_coe_fds_used;
typedef enum SeekTypes typedef enum SeekTypes
{ {
SeekSet = 0, SeekSet = 0,
@ -48,6 +52,71 @@ __libposix_files_check_conf(void)
sysfatal("libposix: no seek translations"); sysfatal("libposix: no seek translations");
} }
void
__libposix_set_close_on_exec(int fd, int close)
{
int i;
if(__libposix_coe_fds_size == __libposix_coe_fds_used){
__libposix_coe_fds_size += 8;
__libposix_coe_fds = realloc(__libposix_coe_fds, __libposix_coe_fds_size * sizeof(int));
i = __libposix_coe_fds_size;
while(i > __libposix_coe_fds_used)
__libposix_coe_fds[--i] = -1;
}
/* remove fd if already present */
i = 0;
while(i < __libposix_coe_fds_size){
if(__libposix_coe_fds[i] == fd){
__libposix_coe_fds[i] = -1;
--__libposix_coe_fds_used;
break;
}
++i;
}
if(close){
/* add fd to close on exec */
i = 0;
while(i < __libposix_coe_fds_size){
if(__libposix_coe_fds[i] == -1){
__libposix_coe_fds[i] = fd;
break;
}
++i;
}
++__libposix_coe_fds_used;
}
}
void
__libposix_close_on_exec(void)
{
int i = 0;
while(i < __libposix_coe_fds_size){
if(__libposix_coe_fds[i] != -1){
close(__libposix_coe_fds[i]);
__libposix_coe_fds[i] = -1;
--__libposix_coe_fds_used;
}
++i;
}
assert(__libposix_coe_fds_used == 0);
free(__libposix_coe_fds);
__libposix_coe_fds = nil;
__libposix_coe_fds_size = 0;
}
int
__libposix_should_close_on_exec(int fd)
{
int i = 0;
while(i < __libposix_coe_fds_size){
if(__libposix_coe_fds[i] == fd)
return 1;
++i;
}
return 0;
}
int int
libposix_translate_open(PosixOpenTranslator translation) libposix_translate_open(PosixOpenTranslator translation)
{ {
@ -746,6 +815,8 @@ libposix_getdents(int *errnop, int fd, char *buf, int buf_bytes)
goto FailWithENOTDIR; /* not a directory */ goto FailWithENOTDIR; /* not a directory */
r = read(fd, buf, buf_bytes); r = read(fd, buf, buf_bytes);
if(r == 0)
return 0;
if(r < 0) if(r < 0)
goto FailWithENOENT; /* removed? */ goto FailWithENOENT; /* removed? */
if(r < MINSTATLEN) if(r < MINSTATLEN)

View File

@ -21,70 +21,83 @@
#include <posix.h> #include <posix.h>
#include "internal.h" #include "internal.h"
typedef union {
int group;
char raw[sizeof(int)];
} IntBuf;
extern int *__libposix_devsignal;
int __libposix_session_leader = -1; int __libposix_session_leader = -1;
static int static int
get_noteid(int *errnop, int pid) get_ppid(int pid)
{ {
int n, f; long n;
char buf[30]; char buf[32];
sprint(buf, "/proc/%d/noteid", pid); sprint(buf, "/proc/%d/ppid", pid);
f = open(buf, OREAD); n = remove(buf);
if(f < 0){ if(n == -1)
*errnop = __libposix_get_errno(PosixEPERM);
return -1; return -1;
} return (int)n;
n = read(f, buf, sizeof(buf) - 1); }
if(n < 0){
*errnop = __libposix_get_errno(PosixEPERM);
return -1;
}
buf[n] = '\0';
n = atoi(buf);
close(f);
return n; long
__libposix_sighelper_set_pgid(int target, int group)
{
union {
PosixHelperRequest request;
long raw;
} offset;
IntBuf buf;
offset.request.command = PHSetProcessGroup;
offset.request.target = target;
buf.group = group;
return pwrite(*__libposix_devsignal, buf.raw, sizeof(buf.raw), offset.raw);
} }
static int static int
set_noteid(int *errnop, int pid, int noteid) set_group_id(int *errnop, int pid, int group)
{ {
int n, f; int mypid, ppid;
char buf[30];
if(pid == 0) if(pid < 0 || group < 0){
pid = getpid(); *errnop = __libposix_get_errno(PosixEINVAL);
if(noteid == 0){
noteid = get_noteid(errnop, pid);
if(noteid < 0)
return noteid;
}
sprint(buf, "/proc/%d/noteid", pid);
f = open(buf, OWRITE);
if(f < 0) {
*errnop = __libposix_get_errno(PosixESRCH);
return -1; return -1;
} }
n = sprint(buf, "%d", noteid); if(pid == __libposix_session_leader){
n = write(f, buf, n);
if(n < 0){
*errnop = __libposix_get_errno(PosixEPERM); *errnop = __libposix_get_errno(PosixEPERM);
return -1; return -1;
} }
close(f); mypid = *__libposix_pid;
return 0; if(pid == 0 && group == 0){
/* the caller wants a new process group */
CreateNewProcessGroup:
rfork(RFNOTEG);
return __libposix_sighelper_cmd(PHSetProcessGroup, mypid);
}
ppid = get_ppid(pid);
if(ppid == -1 || pid != mypid && mypid != ppid){
*errnop = __libposix_get_errno(PosixESRCH);
return -1;
}
if(pid == group && pid == mypid)
goto CreateNewProcessGroup;
return __libposix_sighelper_set_pgid(pid, group);
} }
int int
POSIX_getuid(int *errnop) POSIX_getuid(int *errnop)
{ {
return 0; return 1000;
} }
int int
POSIX_geteuid(int *errnop) POSIX_geteuid(int *errnop)
{ {
return 0; return 1000;
} }
int int
@ -102,7 +115,7 @@ POSIX_seteuid(int *errnop, int euid)
int int
POSIX_setreuid(int *errnop, int ruid, int euid) POSIX_setreuid(int *errnop, int ruid, int euid)
{ {
return 0; return 1000;
} }
int int
@ -138,61 +151,129 @@ POSIX_setregid(int *errnop, int rgid, int egid)
int int
POSIX_getpgrp(int *errnop) POSIX_getpgrp(int *errnop)
{ {
int pid = getpid(); long ret;
return get_noteid(errnop, pid); int pid = *__libposix_pid;
ret = __libposix_sighelper_cmd(PHGetProcessGroupId, pid);
if(ret < 0)
return pid;
return ret;
} }
int int
POSIX_getpgid(int *errnop, int pid) POSIX_getpgid(int *errnop, int pid)
{ {
return get_noteid(errnop, pid); long ret;
ret = __libposix_sighelper_cmd(PHGetProcessGroupId, pid);
if(ret < 0)
*errnop = __libposix_get_errno(PosixESRCH);
return ret;
} }
int int
POSIX_setpgid(int *errnop, int pid, int pgid) POSIX_setpgid(int *errnop, int pid, int pgid)
{ {
if(pid < 0 || pgid < 0){ return set_group_id(errnop, pid, pgid);
*errnop = __libposix_get_errno(PosixEINVAL);
return -1;
}
return set_noteid(errnop, pid, pgid);
} }
int int
POSIX_getsid(int *errnop, int pid) POSIX_getsid(int *errnop, int pid)
{ {
int reqnoteid, mynoteid; int mypid;
long sid;
char buf[32];
if(pid < 0){ if(pid < 0){
FailWithESRCH:
*errnop = __libposix_get_errno(PosixESRCH); *errnop = __libposix_get_errno(PosixESRCH);
return -1; return -1;
} }
snprint(buf, sizeof(buf), "/proc/%d/ns", pid);
if(access(buf, AEXIST) != 0)
goto FailWithESRCH;
mypid = *__libposix_pid;
if(pid == 0) if(pid == 0)
pid = getpid(); pid = mypid;
else if(pid == getpid()) sid = __libposix_sighelper_cmd(PHGetSessionId, pid);
return __libposix_session_leader; if(sid < 0){
reqnoteid = get_noteid(errnop, pid); *errnop = __libposix_get_errno(PosixEPERM);
if(reqnoteid < 0) return -1;
return reqnoteid;
if(__libposix_session_leader < 0)
return reqnoteid;
mynoteid = POSIX_getpgrp(errnop);
if(mynoteid == reqnoteid){
/* if it share our pgrp (aka noteid), it shares
* our session leader
*/
return __libposix_session_leader;
} }
return reqnoteid; if(pid == mypid)
__libposix_session_leader = (int)sid;
return sid;
} }
int int
POSIX_setsid(int *errnop) POSIX_setsid(int *errnop)
{ {
if(rfork(RFNAMEG|RFNOTEG) < 0){ extern PosixSignalMask *__libposix_signal_mask;
*errnop = __libposix_get_errno(PosixEPERM); extern SignalConf *__libposix_signals;
return -1; extern int *__libposix_devsignal;
char *posixly_args[4], *fname;
int mypid = *__libposix_pid;
int oldsid;
long controlpid;
SignalConf *c;
/* detach the previous session */
oldsid = (int)__libposix_sighelper_cmd(PHGetSessionId, 0);
fname = smprint("#s/posixly.%s.%d", getuser(), oldsid);
if(fname == nil || __libposix_sighelper_cmd(PHDetachSession, 0) < 0)
goto FailWithEPERM;
if(*__libposix_devsignal >= 0)
close(*__libposix_devsignal);
*__libposix_devsignal = -1;
rfork(RFNAMEG|RFNOTEG|RFENVG|RFFDG);
unmount(fname, "/dev");
free(fname);
fname = nil;
assert(access("/dev/posix", AEXIST) != 0);
/* start the new session */
switch(controlpid = sys_rfork(RFPROC|RFNOTEG|RFENVG|RFFDG)){
case -1:
goto FailWithEPERM;
case 0:
posixly_args[0] = "posixly";
posixly_args[1] = "-p";
posixly_args[2] = smprint("%d", mypid);
posixly_args[3] = nil;
jehanne_pexec("sys/posixly", posixly_args);
rfork(RFNOWAIT);
sysfatal("pexec sys/posixly");
default:
break;
} }
__libposix_session_leader = POSIX_getpgrp(errnop);
return __libposix_session_leader; /* wait for /dev/posix/ */
fname = smprint("/proc/%d/note", controlpid);
if(fname == nil)
goto FailWithEPERM;
while(access("/dev/posix", AEXIST) != 0 && access(fname, AWRITE) == 0)
sleep(250);
if(access(fname, AWRITE) != 0)
goto FailWithEPERM;
free(fname);
fname = nil;
/* connect to the new session */
__libposix_sighelper_open();
__libposix_sighelper_set(PHBlockSignals, *__libposix_signal_mask);
c = __libposix_signals;
while(c < __libposix_signals + PosixNumberOfSignals){
if(c->handler == (void*)1)
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(1+(c-__libposix_signals)));
++c;
}
__libposix_session_leader = mypid;
return mypid;
FailWithEPERM:
if(fname)
free(fname);
*errnop = __libposix_get_errno(PosixEPERM);
return -1;
} }

View File

@ -24,11 +24,12 @@ extern int *__libposix_errors_codes;
extern WaitList **__libposix_wait_list; extern WaitList **__libposix_wait_list;
extern ChildList **__libposix_child_list; extern ChildList **__libposix_child_list;
static int __initialized; static int __initialized;
static unsigned char signals_to_code[256]; static PosixProcessDisposer __libposix_process_dispose;
static unsigned char code_to_signal[256];
int *__libposix_sigchld_father_pid;
int *__libposix_sigchld_target_pid; int *__libposix_sigchld_child_pid;
int *__libposix_devsignal;
int *__libposix_pid;
static void static void
libposix_check_configuration(void) libposix_check_configuration(void)
@ -36,32 +37,48 @@ libposix_check_configuration(void)
__libposix_errors_check_conf(); __libposix_errors_check_conf();
__libposix_files_check_conf(); __libposix_files_check_conf();
__libposix_processes_check_conf(); __libposix_processes_check_conf();
__libposix_signal_check_conf(); }
void
__libposix_sighelper_open(void)
{
int mypid;
if(*__libposix_devsignal >= 0)
close(*__libposix_devsignal);
mypid = *__libposix_pid;
*__libposix_devsignal = create("/dev/posix/signals", ORDWR|OCEXEC, mypid);
if(*__libposix_devsignal < 0)
sysfatal("cannot create /dev/posix/signals: %r");
} }
void void
libposix_init(int argc, char *argv[], PosixInit init) libposix_init(int argc, char *argv[], PosixInit init)
{ {
extern int main(int, char**); extern int main(int, char**);
extern unsigned char *__signals_to_code_map;
extern unsigned char *__code_to_signal_map;
extern int *__handling_external_signal; extern int *__handling_external_signal;
extern int *__restart_syscall; extern int *__restart_syscall;
extern int *__libposix_sigchld_target_pid; extern PosixSignalMask *__libposix_signal_mask;
WaitList *wait_list; WaitList *wait_list;
ChildList *child_list; ChildList *child_list;
PosixSignalMask signal_mask;
int mypid;
int status; int status;
int error_codes[ERRNO_LAST-ERRNO_FIRST]; int error_codes[ERRNO_LAST-ERRNO_FIRST];
int handling_signal; int handling_signal;
int sigchld_target_pid; int sigchld_father_pid;
int sigchld_child_pid;
int restart_syscall; int restart_syscall;
int devsignal;
assert(__initialized == 0); assert(__initialized == 0);
mypid = getpid();
__libposix_pid = &mypid;
/* initialize PosixErrors map */ /* initialize PosixErrors map */
memset(error_codes, 0, sizeof(error_codes)); memset(error_codes, 0, sizeof(error_codes));
__libposix_errors_codes=error_codes; __libposix_errors_codes = error_codes;
/* initialize wait_list; see also POSIX_fork and POSIX_exit */ /* initialize wait_list; see also POSIX_fork and POSIX_exit */
wait_list = nil; wait_list = nil;
@ -72,28 +89,63 @@ libposix_init(int argc, char *argv[], PosixInit init)
__libposix_child_list = &child_list; __libposix_child_list = &child_list;
/* initialize signal handling */ /* initialize signal handling */
restart_syscall = 0;
handling_signal = 0; handling_signal = 0;
sigchld_target_pid = 0; sigchld_father_pid = 0;
sigchld_child_pid = 0;
signal_mask = 0;
devsignal = -1;
__libposix_devsignal = &devsignal;
__restart_syscall = &restart_syscall; __restart_syscall = &restart_syscall;
__signals_to_code_map = signals_to_code;
__code_to_signal_map = code_to_signal;
__handling_external_signal = &handling_signal; __handling_external_signal = &handling_signal;
__libposix_sigchld_target_pid = &sigchld_target_pid; __libposix_sigchld_father_pid = &sigchld_father_pid;
__libposix_sigchld_child_pid = &sigchld_child_pid;
__libposix_signal_mask = &signal_mask;
__libposix_reset_pending_signals();
if(!atnotify(__libposix_note_handler, 1)) if(!atnotify(__libposix_note_handler, 1))
sysfatal("libposix: atnotify"); sysfatal("libposix: atnotify");
init(); __libposix_sighelper_open();
signal_mask = (PosixSignalMask)__libposix_sighelper_cmd(PHGetProcMask, 0);
__libposix_init_signal_handlers();
init(argc, argv);
libposix_check_configuration(); libposix_check_configuration();
__initialized = 1; __initialized = 1;
status = main(argc, argv); status = main(argc, argv);
if(__libposix_process_dispose != nil)
__libposix_process_dispose(status);
POSIX_exit(status); POSIX_exit(status);
} }
int
libposix_on_process_disposition(PosixProcessDisposer dispose)
{
if(__libposix_process_dispose != nil)
return 0;
__libposix_process_dispose = dispose;
return 1;
}
int int
__libposix_initialized(void) __libposix_initialized(void)
{ {
return __initialized; return __initialized;
} }
long
__libposix_sighelper_cmd(PosixHelperCommand command, int posix_process_pid)
{
union {
PosixHelperRequest request;
long raw;
} offset;
offset.request.command = command;
offset.request.target = posix_process_pid;
return pwrite(*__libposix_devsignal, "", 0, offset.raw);
}

View File

@ -33,10 +33,29 @@ struct ChildList
ChildList *next; ChildList *next;
}; };
typedef struct SignalConf SignalConf;
struct SignalConf
{
void* handler;
PosixSignalMask mask : 56;
int sa_siginfo : 1;
int sa_resethand : 1;
int sa_restart : 1;
int sa_nochildwait : 1;
};
typedef struct PendingSignalList PendingSignalList;
struct PendingSignalList
{
PosixSignalInfo signal;
PendingSignalList* next;
};
extern int *__libposix_pid;
extern void __libposix_files_check_conf(void); extern void __libposix_files_check_conf(void);
extern void __libposix_errors_check_conf(void); extern void __libposix_errors_check_conf(void);
extern void __libposix_processes_check_conf(void); extern void __libposix_processes_check_conf(void);
extern void __libposix_signal_check_conf(void);
extern int __libposix_initialized(void); extern int __libposix_initialized(void);
extern int __libposix_get_errno(PosixError e); extern int __libposix_get_errno(PosixError e);
@ -51,16 +70,75 @@ extern void __libposix_free_wait_list(void);
extern void __libposix_setup_new_process(void); extern void __libposix_setup_new_process(void);
extern int __libposix_note_to_signal(char *note); extern int __libposix_signal_to_note(const PosixSignalInfo *si, char *buf, int size);
extern int __libposix_note_to_signal(const char *note, PosixSignalInfo *siginfo);
extern int __libposix_is_child(int pid); extern int __libposix_is_child(int pid);
extern void __libposix_free_child_list(void);
extern void __libposix_forget_child(int pid); extern void __libposix_forget_child(int pid);
extern int __libposix_send_control_msg(int pid, char *msg); extern int __libposix_send_control_msg(int pid, char *msg);
extern PosixError __libposix_notify_signal_to_process(int pid, int signal); extern PosixError __libposix_notify_signal_to_process(int pid, PosixSignalInfo *siginfo);
extern PosixError __libposix_receive_signal(int sig); extern PosixError __libposix_receive_signal(PosixSignalInfo *siginfo);
extern PosixError __libposix_dispatch_signal(int pid, PosixSignalInfo* siginfo);
extern int __libposix_restart_syscall(void); extern int __libposix_restart_syscall(void);
extern int __libposix_signal_blocked(PosixSignalInfo *siginfo);
extern int __libposix_run_signal_handler(SignalConf *c, PosixSignalInfo *siginfo);
extern void __libposix_reset_pending_signals(void);
extern void __libposix_set_close_on_exec(int fd, int close);
extern int __libposix_should_close_on_exec(int fd);
extern void __libposix_close_on_exec(void);
extern void __libposix_init_signal_handlers(void);
#define SIGNAL_MASK(signal) (1ULL<<((signal)-1))
#define SIGNAL_RAW_ADD(bitmask, signal) (bitmask |= SIGNAL_MASK(signal))
#define SIGNAL_RAW_DEL(bitmask, signal) (bitmask &= ~SIGNAL_MASK(signal))
typedef enum {
PHProcessExited, /* WRITE, for nannies, the child might not be a libposix application */
PHCallingExec, /* WRITE */
PHSignalProcess, /* WRITE */
PHSignalGroup, /* WRITE */
PHSignalForeground, /* WRITE, for the controller process */
PHIgnoreSignal, /* WRITE */
PHEnableSignal, /* WRITE */
PHBlockSignals, /* WRITE */
PHWaitSignals, /* READ, may block */
PHGetSessionId, /* WRITE, ret contains the id */
PHGetProcessGroupId, /* WRITE, ret contains the id */
PHGetPendingSignals, /* WRITE, ret contains the mask */
PHGetProcMask, /* WRITE, ret contains the mask */
PHSetForegroundGroup, /* WRITE */
PHGetForegroundGroup, /* WRITE */
PHDetachSession, /* WRITE */
PHSetProcessGroup, /* WRITE */
} PosixHelperCommand;
typedef struct {
int target;
PosixHelperCommand command;
} PosixHelperRequest;
extern void __libposix_sighelper_open(void);
extern long __libposix_sighelper_cmd(PosixHelperCommand command, int target);
extern long __libposix_sighelper_set(PosixHelperCommand command, PosixSignalMask signal_set);
extern long __libposix_sighelper_signal(PosixHelperCommand command, int target, PosixSignalInfo *siginfo);
extern long __libposix_sighelper_wait(PosixSignalMask set, PosixSignalInfo *siginfo);
extern long __libposix_sighelper_set_pgid(int target, int group_id);

50
sys/src/lib/posix/kill.c Normal file
View File

@ -0,0 +1,50 @@
/*
* This file is part of Jehanne.
*
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3 of the License.
*
* Jehanne 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 General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
*/
#include <u.h>
#include <lib9.h>
#include <posix.h>
#include "internal.h"
int
POSIX_kill(int *errnop, int pid, int signo)
{
PosixError perror;
PosixSignalInfo siginfo;
int errno;
if(signo < 1 || signo > PosixNumberOfSignals){
*errnop = __libposix_get_errno(PosixEINVAL);
return -1;
}
memset(&siginfo, 0, sizeof(PosixSignalInfo));
siginfo.si_signo = signo;
siginfo.si_pid = *__libposix_pid;
siginfo.si_code = PosixSIUser;
siginfo.si_uid = POSIX_getuid(&errno);
if(pid == siginfo.si_pid)
perror = __libposix_receive_signal(&siginfo);
else
perror = __libposix_dispatch_signal(pid, &siginfo);
if(perror != 0){
*errnop = __libposix_get_errno(perror);
return -1;
}
return 0;
}

View File

@ -35,7 +35,8 @@ POSIX_isatty(int *errnop, int fd)
} }
l = strlen(buf); l = strlen(buf);
if(l >= 9 && strcmp(buf+l-9, "/dev/cons") == 0) if((l >= 9 && strcmp(buf+l-9, "/dev/cons") == 0)
||(l >= 8 && strcmp(buf+l-8, "/dev/tty") == 0))
return 1; return 1;
*errnop = __libposix_get_errno(PosixENOTTY); *errnop = __libposix_get_errno(PosixENOTTY);
return 0; return 0;
@ -138,12 +139,14 @@ POSIX_getpass(int *errnop, const char *prompt)
char *p; char *p;
static char buf[256]; static char buf[256];
if(fd2path(0, buf, sizeof(buf)) == 0 && strcmp("/dev/cons", buf) == 0) if(fd2path(0, buf, sizeof(buf)) == 0
&& (strcmp("/dev/cons", buf) == 0 || strcmp("/dev/tty", buf) == 0))
r = 0; r = 0;
else if((r = open("/dev/cons", OREAD)) < 0) else if((r = open("/dev/cons", OREAD)) < 0)
goto ReturnENXIO; goto ReturnENXIO;
if(fd2path(1, buf, sizeof(buf)) == 0 && strcmp("/dev/cons", buf) == 0) if(fd2path(1, buf, sizeof(buf)) == 0
&& (strcmp("/dev/cons", buf) == 0 || strcmp("/dev/tty", buf) == 0))
w = 1; w = 1;
else if((w = open("/dev/cons", OWRITE)) < 0) else if((w = open("/dev/cons", OWRITE)) < 0)
goto CloseRAndReturnENXIO; goto CloseRAndReturnENXIO;

1941
sys/src/lib/posix/posixly.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -55,39 +55,29 @@ int (*__libposix_fork)(int *errnop) = fork_without_sigchld;
void void
__libposix_free_wait_list(void) __libposix_free_wait_list(void)
{ {
WaitList *wl, *c; WaitList *tail, *w;
/* free the wait list as the memory is NOT shared */ /* free the wait list as the memory is NOT shared */
wl = *__libposix_wait_list; tail = *__libposix_wait_list;
if(wl != nil){ while(w = tail){
*__libposix_wait_list = nil; tail = tail->next;
do free(w);
{
c = wl;
wl = c->next;
free(c);
}
while (wl != nil);
} }
*__libposix_wait_list = nil;
} }
void void
__libposix_free_child_list(void) __libposix_free_child_list(void)
{ {
ChildList *l, *c; ChildList *tail, *c;
/* free the wait list as the memory is shared */ /* free the wait list as the memory is shared */
l = *__libposix_child_list; tail = *__libposix_child_list;
if(l != nil){ while(c = tail){
*__libposix_child_list = nil; tail = tail->next;
do free(c);
{
c = l;
l = c->next;
free(c);
}
while (l != nil);
} }
*__libposix_child_list = nil;
} }
int int
@ -112,8 +102,7 @@ __libposix_forget_child(int pid)
/* free the wait list as the memory is shared */ /* free the wait list as the memory is shared */
l = __libposix_child_list; l = __libposix_child_list;
while(*l != nil){ while(c = *l){
c = *l;
if(c->pid == pid){ if(c->pid == pid){
*l = c->next; *l = c->next;
free(c); free(c);
@ -126,9 +115,18 @@ __libposix_forget_child(int pid)
void void
__libposix_setup_new_process(void) __libposix_setup_new_process(void)
{ {
extern PosixSignalMask *__libposix_signal_mask;
*__libposix_pid = getpid();
/* reset wait list for the child */ /* reset wait list for the child */
__libposix_free_wait_list(); __libposix_free_wait_list();
__libposix_free_child_list(); __libposix_free_child_list();
/* clear pending signals; reload mask */
__libposix_reset_pending_signals();
__libposix_sighelper_open();
*__libposix_signal_mask = (PosixSignalMask)__libposix_sighelper_cmd(PHGetProcMask, 0);
} }
void void
@ -178,8 +176,6 @@ POSIX_getrusage(int *errnop, PosixRUsages who, void *r_usagep)
int int
POSIX_execve(int *errnop, const char *name, char * const*argv, char * const*env) POSIX_execve(int *errnop, const char *name, char * const*argv, char * const*env)
{ {
long ret;
// see http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html // see http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
if(env == environ){ if(env == environ){
/* just get a copy of the current environment */ /* just get a copy of the current environment */
@ -190,25 +186,18 @@ POSIX_execve(int *errnop, const char *name, char * const*argv, char * const*env)
} }
__libposix_free_wait_list(); __libposix_free_wait_list();
__libposix_close_on_exec();
__libposix_sighelper_cmd(PHCallingExec, 0);
ret = sys_exec(name, argv); sys_exec(name, argv);
switch(ret){ *errnop = __libposix_translate_errstr((uintptr_t)POSIX_execve);
case 0:
return 0;
case ~0:
*errnop = __libposix_translate_errstr((uintptr_t)POSIX_execve);
break;
default:
*errnop = ret;
break;
}
return -1; return -1;
} }
int int
POSIX_getpid(int *errnop) POSIX_getpid(int *errnop)
{ {
return getpid(); return *__libposix_pid;
} }
int int
@ -223,13 +212,14 @@ POSIX_fork(int *errnop)
return __libposix_fork(errnop); return __libposix_fork(errnop);
} }
int static int
POSIX_wait(int *errnop, int *status) __libposix_wait(int *errnop, int *status, long ms)
{ {
Waitmsg *w; Waitmsg *w;
WaitList *l; WaitList *l;
char *s; char *s, err[ERRMAX];
int ret = 0, sig = 0, pid; int ret = 0, sig = 0, pid;
long wakeup = 0;
l = *__libposix_wait_list; l = *__libposix_wait_list;
if(l != nil){ if(l != nil){
@ -242,10 +232,25 @@ POSIX_wait(int *errnop, int *status)
} }
OnIgnoredSignalInterrupt: OnIgnoredSignalInterrupt:
if(ms)
wakeup = awake(ms);
w = wait(); w = wait();
if(w == nil){ if(w == nil){
if(__libposix_restart_syscall()) rerrstr(err, ERRMAX);
if(strstr(err, "no living children") != nil){
*errnop = __libposix_get_errno(PosixECHILD);
return -1;
}
if(__libposix_restart_syscall()){
if(wakeup)
forgivewkp(wakeup);
goto OnIgnoredSignalInterrupt; goto OnIgnoredSignalInterrupt;
}
if(wakeup){
if(awakened(wakeup))
return 0;
forgivewkp(wakeup);
}
*errnop = __libposix_get_errno(PosixECHILD); *errnop = __libposix_get_errno(PosixECHILD);
return -1; return -1;
} }
@ -283,13 +288,20 @@ POSIX_umask(int *errnop, int mask)
return 0; return 0;
} }
int
POSIX_wait(int *errnop, int *status)
{
return __libposix_wait(errnop, status, 0);
}
int int
POSIX_waitpid(int *errnop, int reqpid, int *status, int options) POSIX_waitpid(int *errnop, int reqpid, int *status, int options)
{ {
Waitmsg *w; Waitmsg *w;
WaitList *c, **nl; WaitList *c, **nl;
char *s; char *s, err[ERRMAX];
int ret = 0, sig = 0, nohang = 0, pid; int ret = 0, sig = 0, pid;
long nohang = 0;
if(options & __libposix_wnohang){ if(options & __libposix_wnohang){
@ -304,10 +316,9 @@ POSIX_waitpid(int *errnop, int reqpid, int *status, int options)
switch(reqpid){ switch(reqpid){
case -1: case -1:
if(nohang){ if(nohang){
*errnop = __libposix_get_errno(PosixEINVAL); return __libposix_wait(errnop, status, 100);
return -1;
} }
return POSIX_wait(errnop, status); return __libposix_wait(errnop, status, 0);
case 0: case 0:
/* not yet implemented; requires changes to Waitmsg */ /* not yet implemented; requires changes to Waitmsg */
*errnop = __libposix_get_errno(PosixEINVAL); *errnop = __libposix_get_errno(PosixEINVAL);
@ -337,13 +348,30 @@ POSIX_waitpid(int *errnop, int reqpid, int *status, int options)
WaitAgain: WaitAgain:
OnIgnoredSignalInterrupt: OnIgnoredSignalInterrupt:
if(nohang)
nohang = awake(100);
w = wait(); w = wait();
if(w == nil){ if(w == nil){
if(__libposix_restart_syscall()) rerrstr(err, ERRMAX);
if(strstr(err, "no living children") != nil){
*errnop = __libposix_get_errno(PosixECHILD);
return -1;
}
if(__libposix_restart_syscall()){
if(nohang)
forgivewkp(nohang);
goto OnIgnoredSignalInterrupt; goto OnIgnoredSignalInterrupt;
}
if(nohang){
if(awakened(nohang))
return 0;
forgivewkp(nohang);
}
*errnop = __libposix_get_errno(PosixECHILD); *errnop = __libposix_get_errno(PosixECHILD);
return -1; return -1;
} }
if(nohang)
forgivewkp(nohang);
pid = w->pid; pid = w->pid;
__libposix_forget_child(pid); __libposix_forget_child(pid);
if(w->msg[0] != 0){ if(w->msg[0] != 0){

View File

@ -21,61 +21,51 @@
#include <posix.h> #include <posix.h>
#include "internal.h" #include "internal.h"
/* rendezvous points */
extern unsigned char *__signals_to_code_map;
extern unsigned char *__code_to_signal_map;
extern ChildList **__libposix_child_list;
/* pointer to the pid to forward notes to */ /* pointer to the pid to forward notes to */
extern int *__libposix_sigchld_target_pid; extern ChildList **__libposix_child_list;
extern WaitList **__libposix_wait_list;
#define CHILD_READY(pid) ((long)rendezvous(&__signals_to_code_map, (void*)(~(pid)))) extern SignalConf *__libposix_signals;
#define C2P_READY(pid) ((long)rendezvous(&__code_to_signal_map, (void*)(~(pid)))) extern int *__libposix_devsignal;
static void static void
release_inherited_resources(void) open_sighelper_nanny(void)
{ {
notify(nil); int mypid;
rfork(RFCNAMEG|RFCENVG|RFNOTEG|RFCFDG); if(*__libposix_devsignal >= 0)
bind("#p", "/proc", MREPL); close(*__libposix_devsignal);
rfork(RFNOMNT); mypid = *__libposix_pid;
*__libposix_devsignal = create("/dev/posix/nanny", OWRITE|OCEXEC, mypid);
if(*__libposix_devsignal < 0)
sysfatal("cannot create /dev/posix/nanny: %r");
} }
static void static void
forwarding_note_handler(void *ureg, char *note) exit_on_SA_NOCLDWAIT(char *msg){
{ /* we share the father's memory, we can inspect its configuration */
extern int __min_known_sig; if(__libposix_signals[PosixSIGCHLD-1].sa_nochildwait){
extern int __max_known_sig; /* the parent does not care about us*/
int sig; rfork(RFNOWAIT);
PosixSignals signal; exits(msg);
if(strncmp(note, __POSIX_SIGNAL_PREFIX, __POSIX_SIGNAL_PREFIX_LEN) == 0){
sig = __libposix_note_to_signal(note);
if(sig < __min_known_sig || sig > __max_known_sig){
/* Ignore unknown signals */
noted(NCONT);
}
signal = __code_to_signal_map[sig];
__libposix_notify_signal_to_process(*__libposix_sigchld_target_pid, sig);
if(signal == PosixSIGCONT)
__libposix_send_control_msg(*__libposix_sigchld_target_pid, "start");
noted(NCONT);
} else {
/* what happened? */
noted(NDFLT);
} }
} }
static void static void
forward_wait_msg(int sigchld_receiver, char *name) forward_wait_msg(int father, int child)
{ {
int n; int n, mypid;
char buf[512], err[ERRMAX], note[512], *fld[5]; PosixSignalInfo si;
char buf[512], err[ERRMAX], note[512], *fld[5], *tmp, *name;
snprint(buf, sizeof(buf), "/proc/%d/args", getpid()); mypid = *__libposix_pid;
name = smprint("signal proxy %d <> %d", father, child);
snprint(buf, sizeof(buf), "/proc/%d/args", mypid);
n = open(buf, OWRITE); n = open(buf, OWRITE);
write(n, name, strlen(name)+1); write(n, name, strlen(name)+1);
close(n); close(n);
rfork(RFCNAMEG|RFCENVG|RFNOMNT);
n = 0; n = 0;
WaitInterrupted: WaitInterrupted:
n = await(buf, sizeof buf-1); n = await(buf, sizeof buf-1);
@ -84,21 +74,45 @@ WaitInterrupted:
if(strstr(err, "no living children") == nil) if(strstr(err, "no living children") == nil)
goto WaitInterrupted; goto WaitInterrupted;
snprint(note, sizeof(note), "%s: %r", name); snprint(note, sizeof(note), "%s: %r", name);
if(sigchld_receiver) exit_on_SA_NOCLDWAIT(note);
postnote(PNPROC, sigchld_receiver, note); postnote(PNPROC, father, note);
__libposix_sighelper_cmd(PHProcessExited, child);
exits(note); exits(note);
} }
buf[n] = '\0'; buf[n] = '\0';
if(jehanne_tokenize(buf, fld, nelem(fld)) != nelem(fld)){ if(jehanne_tokenize(buf, fld, nelem(fld)) != nelem(fld)){
snprint(note, sizeof(note), "%s: couldn't parse wait message", name); snprint(note, sizeof(note), "%s: can not parse wait msg: %s", name, buf);
if(sigchld_receiver) exit_on_SA_NOCLDWAIT(note);
postnote(PNPROC, sigchld_receiver, note); postnote(PNPROC, father, note);
exits(note); exits(note);
} }
snprint(note, sizeof(note), __POSIX_SIGNAL_PREFIX " %d", __signals_to_code_map[PosixSIGCHLD]); memset(&si, 0, sizeof(PosixSignalInfo));
if(sigchld_receiver){ si.si_pid = mypid;
postnote(PNPROC, sigchld_receiver, note); si.si_signo = PosixSIGCHLD;
} si.si_code = PosixSIChildExited;
si.si_uid = POSIX_getuid(&n);
tmp = fld[4];
if(tmp == nil || tmp[0] == '\0')
n = 0;
else if(strcmp(__POSIX_EXIT_PREFIX, tmp) == 0)
n = atoi(tmp + (sizeof(__POSIX_EXIT_PREFIX)/sizeof(char) - 1));
else if(strcmp(__POSIX_EXIT_SIGNAL_PREFIX, tmp) == 0){
n = atoi(tmp + (sizeof(__POSIX_EXIT_SIGNAL_PREFIX)/sizeof(char) - 1));
if(n == PosixSIGTRAP)
si.si_code = PosixSIChildTrapped;
else
si.si_code = PosixSIChildKilled;
} else
n = 127;
si.si_status = n;
exit_on_SA_NOCLDWAIT("SIGCHLD explicity ignored by parent");
__libposix_notify_signal_to_process(father, &si);
__libposix_sighelper_cmd(PHProcessExited, child);
if(n == 0)
exits(nil);
exits(fld[4]); exits(fld[4]);
} }
@ -106,99 +120,76 @@ WaitInterrupted:
static int static int
fork_with_sigchld(int *errnop) fork_with_sigchld(int *errnop)
{ {
int father = getpid(); int proxy, father, child = -1;
int p2c;
long c2p = -1, child = -1;
char proxy_name[256];
ChildList *c; ChildList *c;
uint64_t rend;
char *buf;
/* Father here: /* Father here:
* - create P2C * - create proxy
* - wait for C2P to be ready * - wait for child to be ready
* - register P2C in children list * - register proxy in children list
* - return P2C pid * - return proxy pid
*/ */
switch(p2c = rfork(RFPROC|RFMEM)){ father = getpid();
switch(proxy = rfork(RFPROC|RFMEM|RFFDG)){
case -1: case -1:
return -1; return -1;
case 0: case 0:
/* P2C here: /* proxy here:
* - create C2P * - create child
* - wait for the child pid * - start waiting
* - release all inherited resources
* - install forwarding_note_handler
* - send to father the C2P pid
* - start waiting for the child
*/ */
switch(c2p = rfork(RFPROC|RFMEM)){ *__libposix_pid = getpid();
open_sighelper_nanny();
switch(child = rfork(RFPROC|RFFDG)){
case -1: case -1:
while(C2P_READY(-2) == -1) rend = *__libposix_pid;
; while(rendezvous((void*)rend, "e") == (void*)-1)
exits("rfork (c2p)"); sleep(100);
rfork(RFNOWAIT);
exits("rfork (child)");
case 0: case 0:
/* C2P here: /* Beloved child here
* - create child
* - wait for it to get a copy of everything
* - release all inherited resources
* - install forwarding_note_handler
* - send to P2C the child pid
* - start forwarding notes to the father
*/ */
switch(child = fork()){ __libposix_setup_new_process();
case -1: rend = *__libposix_pid;
while(CHILD_READY(-2) == -1) while(rendezvous((void*)rend, "d") == (void*)-1)
; sleep(100);
exits("rfork (child)"); rfork(RFREND);
case 0: return 0;
/* Beloved child here
*/
__libposix_setup_new_process();
return 0;
default:
release_inherited_resources();
*__libposix_sigchld_target_pid = father;
notify(forwarding_note_handler);
snprint(proxy_name, sizeof(proxy_name), "libposix signal proxy %d < %d", father, child);
while(CHILD_READY(child) == -1)
;
forward_wait_msg(father, proxy_name);
}
default: default:
while((child = CHILD_READY(-3)) == -1) rend = child;
; while((buf = rendezvous((void*)rend, "")) == (void*)-1)
child = ~child; sleep(100);
if(child < 0){ rend = *__libposix_pid;
while(C2P_READY(-2) == -1) while(rendezvous((void*)rend, "d") == (void*)-1)
; sleep(100);
waitpid();
exits("rfork (child)"); /* we share the memory of the parent but we do
} * not need these that fortunately are on the private stack
release_inherited_resources(); */
*__libposix_sigchld_target_pid = child; *__libposix_wait_list = nil;
notify(forwarding_note_handler); *__libposix_child_list = nil;
snprint(proxy_name, sizeof(proxy_name), "libposix signal proxy %d > %d", father, child); forward_wait_msg(father, child);
while(C2P_READY(c2p) == -1)
;
forward_wait_msg(0, proxy_name);
} }
default: default:
while((c2p = C2P_READY(-3)) == -1) rend = proxy;
; while((buf = rendezvous((void*)rend, "")) == (void*)-1)
c2p = ~c2p; sleep(100);
if(c2p < 0){ if(buf[0] == 'e')
waitpid();
return -1; return -1;
}
break; break;
} }
/* no need to lock: the child list is private */ /* no need to lock: the child list is private */
c = malloc(sizeof(ChildList)); c = malloc(sizeof(ChildList));
c->pid = p2c; c->pid = proxy;
c->next = *__libposix_child_list; c->next = *__libposix_child_list;
*__libposix_child_list = c; *__libposix_child_list = c;
return p2c; return proxy;
} }
int int

View File

@ -19,22 +19,25 @@
/* POSIX signals have weird semantics that are hard to emulate in a /* POSIX signals have weird semantics that are hard to emulate in a
* sane system without giving up on its sanity. * sane system without giving up on its sanity.
* *
* We distinguish control signals (SIGKILL, SIGSTOP, SIGCONT, * We distinguish control signals (SIGKILL, SIGSTOP, SIGTSTP, SIGCONT,
* SIGABRT, SIGIOT), SIGCHLD/SIGCLD, timers' wakeups * SIGABRT, SIGTTIN, SIGTTOU, SIGIOT), SIGCHLD/SIGCLD, timers' wakeups
* (SIGALRM, SIGPROF, SIGVTALRM) and all the others. * (SIGALRM, SIGPROF, SIGVTALRM) and all the others.
* *
* TRASMISSION * TRASMISSION
* ----------- * -----------
* Signal transmission depends on the relation between the sender * Signal transmission is done though a file server mounted /dev/posix/,
* and the receiver: * provided by sys/posixly. On startup and at each fork, processes
* 1) if sender and receiver have no relation the signal is translated * create a file named /dev/posix/signal with ORDWR mode and perm
* to a note and sent to the receiver(s); * equals to their pid. Writing and Reading such file they can
* 2) if sender == receiver the signal trampoline is directly invoked * control signal dispatching, process groups and so on.
* for all signals except control ones and the default disposition occurs if *
* the trampoline does not handle the signal * When a signal is written to /dev/posix/signal, it is translated for
* 3) if sender is parent or child of receiver the transmision * each receiver to a note, and written to the specific note file.
* differs from the default if libposix_emulate_SIGCHLD() has been *
* called during library initialization * If the receiver is a known process, the note is in the format
* posix: si_signo si_pid si_uid si_value si_code
* otherwise, if possible, it is translated to an idiomatic note
* (eg "interrupt" or "alarm").
* *
* Since notes in Jehanne are not reentrant, signals translated to * Since notes in Jehanne are not reentrant, signals translated to
* notes will be enqueued in kernel. A special machinery is implemented * notes will be enqueued in kernel. A special machinery is implemented
@ -53,14 +56,15 @@
* ---------------- * ----------------
* Control messages are translated by the receiver to equivalent actions: * Control messages are translated by the receiver to equivalent actions:
* - SIGKILL => write "kill" to the control file of the current process * - SIGKILL => write "kill" to the control file of the current process
* - SIGSTOP => write "stop" to the control file of the current process * - SIGSTOP, SIGTSTP, SIGTTOU, SIGTTIN
* => write "stop" to the control file of the current process
* (when the signal is not handled nor ignored)
* - SIGABRT/SIGIOT => invoke the registered signal handlers and abort * - SIGABRT/SIGIOT => invoke the registered signal handlers and abort
* the current process * the current process
* - SIGCONT => invoke the registered signal handlers via the signal * - SIGCONT => invoke the registered signal handlers via the signal
* trampoline and continue; note that (since a stopped * trampoline and continue; note that (since a stopped
* process cannot resume itself) the sender will write * process cannot resume itself) sys/posixly will write
* "start" to the control file of the receiver before * "start" to the control file of the receiver.
* sending the note (unless SIGCHLD emulation is enable).
* *
* SIGCHLD/SIGCLD * SIGCHLD/SIGCLD
* -------------- * --------------
@ -72,30 +76,26 @@
* *
* Such emulation changes the way POSIX_fork and POSIX_kill works. * Such emulation changes the way POSIX_fork and POSIX_kill works.
* *
* Each fork() will spawn two additional processes that are designed * Each fork() will spawn an additional process that share the memory
* to proxy signals between the parent and the desired child: * of the parent, and waits for the child, so that it can send SIGCHLD:
* *
* parent * parent
* +- proxy from parent to child (P2C) * +- nanny
* +- proxy from child to parent (C2P) * +- child
* +- child *
* Such "nannies" connect to sys/posixly by creating /dev/posix/nanny
* so that the filesystem will handle them differently:
* - any signal for the nanny sent from the parent is delivered to the child
* - any signal for the nanny sent from the child is delivered to the parent
* - any signal for the nanny sent from anybody else is delivered to the child
* *
* Fork will return the pid of P2C to the parent, so that the
* parent process will see the first proxy as its child; the child will
* see the second as its parent. Each proxy waits for its child and
* forwards the notes it receive to its designed target.
* Finally fork in child will return 0. * Finally fork in child will return 0.
* *
* When the child exits, C2P will send a SIGCHLD note to parent and * When the child exits, the proxy will send a SIGCHLD sigchld to parent
* then exit with the same status. Then P2C will exit with * and then exit with the same status.
* the same status too.
* *
* As the parent process will see P2C as its child, it will send any * As the parent process will see the proxy as its child, it will send
* signal to it via kill and will wait it on SIGCHLD. * any signal to it via kill or sigqueue and will wait it on SIGCHLD.
* However, when this machinary is enabled, kill will treat all signals
* for forked children in the same way, sending them to P2C.
* It's P2C's responsibility to translate control messages as required,
* so that SIGCONT will work as expected.
* *
* TIMERS * TIMERS
* ------ * ------
@ -104,6 +104,7 @@
* expire in a signal handler (interrupting a blocking syscall) but * expire in a signal handler (interrupting a blocking syscall) but
* without giving up the simplicity of notes. * without giving up the simplicity of notes.
* *
* (TO BE IMPLEMENTED: )
* We allocate these timers on libposix initialization. When normal * We allocate these timers on libposix initialization. When normal
* code is running timers will be implemented via Jehanne's alarms, * code is running timers will be implemented via Jehanne's alarms,
* producing a note on expiration that will be mapped to the proper * producing a note on expiration that will be mapped to the proper
@ -122,16 +123,22 @@
#include <posix.h> #include <posix.h>
#include "internal.h" #include "internal.h"
unsigned char *__signals_to_code_map;
unsigned char *__code_to_signal_map;
int *__handling_external_signal; int *__handling_external_signal;
int *__restart_syscall; int *__restart_syscall;
extern PosixSignalMask *__libposix_signal_mask;
extern int *__libposix_devsignal;
static int __sigrtmin; typedef union {
static int __sigrtmax; PosixSignalInfo signal;
int __min_known_sig; char raw[sizeof(PosixSignalInfo)];
int __max_known_sig; } SignalBuf;
static PosixSignalTrampoline __libposix_signal_trampoline; typedef union {
PosixSignalMask signals;
char raw[sizeof(PosixSignalMask)];
} SigSetBuf;
static SignalConf signal_configurations[PosixNumberOfSignals];
SignalConf *__libposix_signals = signal_configurations;
typedef enum PosixSignalDisposition typedef enum PosixSignalDisposition
{ {
@ -143,23 +150,37 @@ typedef enum PosixSignalDisposition
} PosixSignalDisposition; } PosixSignalDisposition;
static PosixError static PosixError
note_all_writable_processes(int sig) note_all_writable_processes(PosixSignalInfo* siginfo)
{ {
// TODO: loop over writable note files and post note. // TODO: loop over writable note files and post note.
return PosixEPERM; return PosixEPERM;
} }
static void static void
terminated_by_signal(int sig) terminated_by_signal(int signo)
{ {
char buf[64]; char buf[64];
__libposix_free_wait_list(); __libposix_free_wait_list();
snprint(buf, sizeof(buf), __POSIX_EXIT_SIGNAL_PREFIX "%d", sig); snprint(buf, sizeof(buf), __POSIX_EXIT_SIGNAL_PREFIX "%d", signo);
exits(buf); exits(buf);
} }
void
__libposix_init_signal_handlers(void)
{
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(PosixSIGCHLD));
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(PosixSIGURG));
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(PosixSIGWINCH));
__libposix_signals[PosixSIGCHLD-1].handler = (void*)1;
__libposix_signals[PosixSIGCHLD-1].sa_restart = 1;
__libposix_signals[PosixSIGURG-1].handler = (void*)1;
__libposix_signals[PosixSIGURG-1].sa_restart = 1;
__libposix_signals[PosixSIGWINCH-1].handler = (void*)1;
__libposix_signals[PosixSIGWINCH-1].sa_restart = 1;
}
int int
__libposix_send_control_msg(int pid, char *msg) __libposix_send_control_msg(int pid, char *msg)
{ {
@ -189,7 +210,7 @@ ErrorBeforeOpen:
/* Executes a PosixSignalDisposition. /* Executes a PosixSignalDisposition.
*/ */
static int static int
execute_disposition(int sig, PosixSignalDisposition action) execute_disposition(int signo, PosixSignalDisposition action)
{ {
int aborted_by_signal; int aborted_by_signal;
@ -199,32 +220,27 @@ execute_disposition(int sig, PosixSignalDisposition action)
*__restart_syscall = 1; *__restart_syscall = 1;
return 1; return 1;
case TerminateTheProcess: case TerminateTheProcess:
terminated_by_signal(sig); terminated_by_signal(signo);
break; break;
case TerminateTheProcessAndCoreDump: case TerminateTheProcessAndCoreDump:
aborted_by_signal = 0; aborted_by_signal = 0;
assert(aborted_by_signal); assert(aborted_by_signal);
break; break;
case StopTheProcess: case StopTheProcess:
return __libposix_send_control_msg(getpid(), "stop"); return __libposix_send_control_msg(*__libposix_pid, "stop");
} }
return 0; return 0;
} }
static PosixSignalDisposition static PosixSignalDisposition
default_signal_disposition(int code) default_signal_disposition(PosixSignals signal)
{ {
PosixSignals signal; if(signal >= PosixSIGRTMIN && signal <= PosixSIGRTMAX)
// see http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html
if(__sigrtmin != 0 && __sigrtmax != 0
&&(code >= __sigrtmin || code <= __sigrtmax))
return TerminateTheProcess; return TerminateTheProcess;
signal = __code_to_signal_map[code];
switch(signal){ switch(signal){
default: default:
sysfatal("libposix: undefined signal %d", code); sysfatal("libposix: undefined signal %d", signal);
case PosixSIGALRM: case PosixSIGALRM:
case PosixSIGHUP: case PosixSIGHUP:
@ -255,7 +271,6 @@ default_signal_disposition(int code)
case PosixSIGXFSZ: case PosixSIGXFSZ:
return TerminateTheProcessAndCoreDump; return TerminateTheProcessAndCoreDump;
case PosixSIGCHLD: case PosixSIGCHLD:
case PosixSIGCLD:
case PosixSIGURG: case PosixSIGURG:
return IgnoreWithNoEffect; return IgnoreWithNoEffect;
case PosixSIGCONT: case PosixSIGCONT:
@ -263,209 +278,360 @@ default_signal_disposition(int code)
} }
} }
PosixError /* returns 1 if the signal handling has been completed, 0 otherwise */
__libposix_receive_signal(int sig) int
__libposix_run_signal_handler(SignalConf *c, PosixSignalInfo *siginfo)
{ {
PosixSignalAction action = SignalDefault; PosixSigHandler h;
PosixSignals psig = __code_to_signal_map[sig]; PosixSigAction a;
PosixSignalDisposition disposition; PosixSignalMask m;
if(psig != PosixSIGKILL && psig != PosixSIGSTOP)
action = __libposix_signal_trampoline(sig);
if(psig == PosixSIGABRT)
action = SignalDefault; // lets abort despite the user will
switch(action){ switch((uintptr_t)c->handler){
case SignalCatched: case 0:
/* SIG_DFL */
if(c->sa_restart)
*__restart_syscall = 1;
break; break;
case SignalIgnored: case 1:
/* SIG_IGN */
if(siginfo->si_signo == PosixSIGABRT)
break;
*__restart_syscall = 1; *__restart_syscall = 1;
break; return 1;
case SignalDefault: default:
disposition = default_signal_disposition(sig); m = *__libposix_signal_mask;
if(!execute_disposition(sig, disposition)) *__libposix_signal_mask |= c->mask;
return PosixEPERM; __libposix_sighelper_set(PHBlockSignals, *__libposix_signal_mask);
break; a = c->handler;
case SignalError: h = c->handler;
return PosixEINVAL;
if(c->sa_resethand)
c->handler = 0;
if(c->sa_siginfo){
a(siginfo->si_signo, siginfo, nil);
} else {
h(siginfo->si_signo);
}
if(c->sa_restart)
*__restart_syscall = 1;
*__libposix_signal_mask = m;
__libposix_sighelper_set(PHBlockSignals, *__libposix_signal_mask);
if(siginfo->si_signo == PosixSIGABRT)
break;
return 1;
} }
return 0; return 0;
} }
PosixError PosixError
__libposix_notify_signal_to_process(int pid, int signal) __libposix_receive_signal(PosixSignalInfo *siginfo)
{ {
char buf[128]; SignalConf *c;
int fd, n; PosixSignalDisposition disposition;
PosixSignals signo = siginfo->si_signo;
snprint(buf, sizeof(buf), "/proc/%d/note", pid); if(signo == PosixSIGKILL || signo == PosixSIGSTOP)
if((fd = open(buf, OWRITE)) < 0){ goto ExecuteDefaultDisposition;
if(access(buf, AEXIST) == 0)
return PosixEPERM; if(__libposix_signal_blocked(siginfo))
else return 0;
return PosixESRCH;
} c = __libposix_signals + (signo-1);
n = snprint(buf, sizeof(buf), __POSIX_SIGNAL_PREFIX "%d", signal); if(__libposix_run_signal_handler(c, siginfo))
write(fd, buf, n); return 0;
close(fd);
ExecuteDefaultDisposition:
disposition = default_signal_disposition(signo);
if(!execute_disposition(signo, disposition))
return PosixEPERM;
return 0; return 0;
} }
static PosixError long
notify_signal_to_group(int pid, int signal) __libposix_sighelper_signal(PosixHelperCommand command, int posix_process_pid, PosixSignalInfo *siginfo)
{ {
char buf[128]; union {
int fd, n; PosixHelperRequest request;
long raw;
} offset;
char buf[sizeof(PosixSignalInfo)];
snprint(buf, sizeof(buf), "/proc/%d/notepg", pid); offset.request.command = command;
if((fd = open(buf, OWRITE)) < 0){ offset.request.target = posix_process_pid;
if(access(buf, AEXIST) == 0)
return PosixEPERM; memcpy(buf, siginfo, sizeof(buf));
else
return PosixESRCH; return pwrite(*__libposix_devsignal, buf, sizeof(buf), offset.raw);
} }
n = snprint(buf, sizeof(buf), __POSIX_SIGNAL_PREFIX "%d", signal);
write(fd, buf, n); long
close(fd); __libposix_sighelper_set(PosixHelperCommand command, PosixSignalMask signal_set)
return 0; {
union {
PosixHelperRequest request;
long raw;
} offset;
union {
PosixSignalMask mask;
char raw[sizeof(PosixSignalMask)];
} buffer;
offset.request.command = command;
offset.request.target = 0;
buffer.mask = signal_set;
return pwrite(*__libposix_devsignal, buffer.raw, sizeof(buffer.raw), offset.raw);
}
PosixError
__libposix_notify_signal_to_process(int pid, PosixSignalInfo *siginfo)
{
long e = __libposix_sighelper_signal(PHSignalProcess, pid, siginfo);
return (PosixError)e;
} }
static PosixError static PosixError
dispatch_signal(int pid, int sig) notify_signal_to_group(int pid, PosixSignalInfo* siginfo)
{
long e = __libposix_sighelper_signal(PHSignalGroup, pid, siginfo);
return (PosixError)e;
}
PosixError
__libposix_dispatch_signal(int pid, PosixSignalInfo* siginfo)
{ {
PosixSignals signal;
PosixError error; PosixError error;
switch(pid){ switch(pid){
case 0: case 0:
return notify_signal_to_group(getpid(), sig); return notify_signal_to_group(*__libposix_pid, siginfo);
case -1: case -1:
return note_all_writable_processes(sig); return note_all_writable_processes(siginfo);
default: default:
if(pid < 0) if(pid < 0)
return notify_signal_to_group(-pid, sig); return notify_signal_to_group(-pid, siginfo);
break; break;
} }
signal = __code_to_signal_map[sig]; error = __libposix_notify_signal_to_process(pid, siginfo);
error = __libposix_notify_signal_to_process(pid, sig); if(siginfo->si_signo == PosixSIGCONT && !__libposix_is_child(pid))
if(signal == PosixSIGCONT && !__libposix_is_child(pid))
__libposix_send_control_msg(pid, "start"); __libposix_send_control_msg(pid, "start");
return error; return error;
} }
int static int
POSIX_kill(int *errnop, int pid, int sig) translate_jehanne_kernel_note(const char *note, PosixSignalInfo *siginfo)
{ {
PosixSignals signal; char *trap[3];
PosixError perror; char *tmp;
signal = __code_to_signal_map[sig]; assert(siginfo->si_signo == 0);
if(signal == 0
&&(__sigrtmin != 0 && __sigrtmax != 0) if(strncmp("trap: fault ", note, 12) == 0){
&&(sig < __sigrtmin || sig > __sigrtmax)) // trap: fault read addr=0x0 pc=0x400269
sysfatal("libposix: undefined signal %d", sig); note += 12;
if(pid == getpid()) siginfo->si_signo = PosixSIGTRAP;
perror = __libposix_receive_signal(sig); tmp = strdup(note);
else if(getfields(tmp, trap, 3, 1, " ") == 3){
perror = dispatch_signal(pid, sig); if(trap[0][0] == 'r')
if(perror != 0){ siginfo->si_code = PosixSIFaultMapError;
*errnop = __libposix_get_errno(perror); else
return -1; siginfo->si_code = PosixSIFaultAccessError;
siginfo->si_value._sival_raw = atoll(trap[1]+5);
}
free(tmp);
} else if(strncmp("write on closed pipe", note, 20) == 0){
// write on closed pipe pc=0x400269
siginfo->si_signo = PosixSIGPIPE;
note += 24;
siginfo->si_value._sival_raw = atoll(note);
} else if(strncmp("bad address in syscall", note, 22) == 0){
// bad address in syscall pc=0x41cc54
siginfo->si_signo = PosixSIGSEGV;
note += 26;
siginfo->si_value._sival_raw = atoll(note);
} }
return 0; // TODO: implement
return siginfo->si_signo == 0 ? 0 : 1;
} }
static int static int
translate_jehanne_note(char *note) translate_jehanne_note(const char *note, PosixSignalInfo *siginfo)
{ {
// TODO: implement if(note == nil || note[0] == 0)
return 0;
if(strncmp("alarm", note, 5) == 0){
siginfo->si_signo = PosixSIGALRM;
return 1;
}
if(strncmp("sys: ", note, 5) == 0)
return translate_jehanne_kernel_note(note + 5, siginfo);
if(strncmp("interrupt", note, 9) == 0){
siginfo->si_signo = PosixSIGINT;
return 1;
}
if(strncmp("hangup", note, 6) == 0){
siginfo->si_signo = PosixSIGHUP;
return 1;
}
return 0; return 0;
} }
int int
__libposix_note_to_signal(char *note) __libposix_signal_to_note(const PosixSignalInfo *si, char *buf, int size)
{ {
return atoi(note+__POSIX_SIGNAL_PREFIX_LEN); return
snprint(buf, size, __POSIX_SIGNAL_PREFIX "%d %d %d %#p %d",
si->si_signo, si->si_pid, si->si_uid,
si->si_value._sival_raw, si->si_code);
}
/* The format of a note sent by libposix as a signal is
*
* "posix: %d %d %d %#p %d", signo, pid, uid, value, code
*/
int
__libposix_note_to_signal(const char *note, PosixSignalInfo *siginfo)
{
assert(siginfo->si_signo == 0); /* siginfo must be zeroed */
if(strncmp(note, __POSIX_SIGNAL_PREFIX, __POSIX_SIGNAL_PREFIX_LEN) != 0)
return translate_jehanne_note(note, siginfo);
char *rest = (char*)note + __POSIX_SIGNAL_PREFIX_LEN;
if(*rest == 0)
return 0;
siginfo->si_signo = strtol(rest, &rest, 0);
if(*rest == 0)
return 1;
siginfo->si_pid = strtol(rest, &rest, 0);
if(*rest == 0)
return 1;
siginfo->si_uid = strtoul(rest, &rest, 0);
if(*rest == 0)
return 1;
siginfo->si_value._sival_raw = strtoull(rest, &rest, 0);
if(*rest == 0)
return 1;
siginfo->si_code = strtoul(rest, &rest, 0);
return 1;
} }
int int
__libposix_note_handler(void *ureg, char *note) __libposix_note_handler(void *ureg, char *note)
{ {
int sig; PosixSignalInfo siginfo;
PosixError error; PosixError error;
if(strncmp(note, __POSIX_SIGNAL_PREFIX, __POSIX_SIGNAL_PREFIX_LEN) != 0)
return translate_jehanne_note(note); // TODO: should we translate common notes? memset(&siginfo, 0, sizeof(PosixSignalInfo));
sig = __libposix_note_to_signal(note);
if(sig < __min_known_sig || sig > __max_known_sig) if(!__libposix_note_to_signal(note, &siginfo)
&& (siginfo.si_signo < 1 || siginfo.si_signo > PosixNumberOfSignals))
sysfatal("libposix: '%s' does not carry a signal", note); sysfatal("libposix: '%s' does not carry a signal", note);
*__handling_external_signal = 1; *__handling_external_signal = 1;
error = __libposix_receive_signal(sig); error = __libposix_receive_signal(&siginfo);
*__handling_external_signal = 0; *__handling_external_signal = 0;
werrstr("interrupted");
return error == 0; return error == 0;
} }
int
libposix_define_realtime_signals(int sigrtmin, int sigrtmax)
{
if(sigrtmin >= 256 || sigrtmin <=0)
sysfatal("libposix: invalid SIGRTMIN %d (must be positive and less then 256)", sigrtmin);
if(sigrtmax >= 256 || sigrtmax <=0)
sysfatal("libposix: invalid SIGRTMAX %d (must be positive and less then 256)", sigrtmax);
if(sigrtmax <= sigrtmin)
sysfatal("libposix: invalid SIGRTMAX %d (must be greater than SIGRTMIN %d)", sigrtmax, sigrtmin);
if(__libposix_initialized())
return 0;
__sigrtmin = sigrtmin;
__sigrtmax = sigrtmax;
if(sigrtmin < __min_known_sig || __min_known_sig == 0)
__min_known_sig = sigrtmin;
if(sigrtmax > __max_known_sig || __max_known_sig == 0)
__max_known_sig = sigrtmax;
return 1;
}
int
libposix_define_signal(PosixSignals signal, int code)
{
if(signal >= PosixNumberOfSignals)
sysfatal("libposix: unknown PosixSignal %d", signal);
if(code >= 256 || code <=0)
sysfatal("libposix: invalid signal number %d (must be positive and less then 256)", code);
if(__libposix_initialized())
return 0;
__signals_to_code_map[signal] = (unsigned char)code;
if(signal != PosixSIGCLD || code != __signals_to_code_map[PosixSIGCHLD]){
/* if SIGCHLD == SIGCLD then we use PosixSIGCHLD to identify the signal */
__code_to_signal_map[code] = (unsigned char)signal;
}
if(code < __min_known_sig || __min_known_sig == 0)
__min_known_sig = code;
if(code > __max_known_sig || __max_known_sig == 0)
__max_known_sig = code;
return 1;
}
int
libposix_set_signal_trampoline(PosixSignalTrampoline trampoline)
{
if(__libposix_initialized())
return 0;
if(trampoline == nil)
return 0;
__libposix_signal_trampoline = trampoline;
return 1;
}
int int
__libposix_restart_syscall(void) __libposix_restart_syscall(void)
{ {
int r = *__restart_syscall; int r;
if(*__handling_external_signal)
return 0;
r = *__restart_syscall;
*__restart_syscall = 0; *__restart_syscall = 0;
return r; return r;
} }
void int
__libposix_signal_check_conf(void) POSIX_sigaction(int *errnop, int signo, const struct sigaction *act, struct sigaction *old)
{ {
if(__libposix_signal_trampoline == nil) SignalConf *c, oconf;
sysfatal("libposix: no signal trampoline");
if(signo < 1 || signo > PosixNumberOfSignals)
goto FailWithEINVAL;
c = __libposix_signals + (signo-1);
if(old)
memcpy(&oconf, c, sizeof(SignalConf));
if(act){
memset(c, 0, sizeof(SignalConf));
if(signo == PosixSIGKILL || signo == PosixSIGSTOP)
goto FailWithEINVAL;
if(act->sa_flags & PosixSAFSigInfo){
c->sa_siginfo = 1;
c->handler = act->sa_sigaction;
} else {
c->handler = act->sa_handler;
}
c->mask = act->sa_mask & ~((255UL<<56) | SIGNAL_MASK(PosixSIGKILL) | SIGNAL_MASK(PosixSIGSTOP));
if(act->sa_flags & PosixSAFResetHandler)
c->sa_resethand = 1;
else
c->sa_resethand = 0;
if(act->sa_flags & PosixSAFRestart)
c->sa_restart = 1;
else
c->sa_restart = 0;
if(signo == PosixSIGCHLD){
if(act->sa_flags & PosixSAFNoChildrenWait)
c->sa_nochildwait = 1;
else
c->sa_nochildwait = 0;
if(c->handler == (void*)1) /* SIGCHLD && SIG_IGN => SA_NOCLDWAIT */
c->sa_nochildwait = 1;
}
if(c->handler == (void*)1){
/* ignore signal */
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(signo));
} else if(c->handler == (void*)0){
/* default behavior */
switch(signo){
case PosixSIGCHLD:
case PosixSIGURG:
case PosixSIGWINCH:
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(signo));
break;
default:
__libposix_sighelper_set(PHEnableSignal, SIGNAL_MASK(signo));
break;
}
} else {
/* do not ignore signal */
__libposix_sighelper_set(PHEnableSignal, SIGNAL_MASK(signo));
}
}
if(old){
if(oconf.sa_siginfo){
old->sa_sigaction = oconf.handler;
old->sa_mask = oconf.mask;
old->sa_flags = 0;
if(oconf.sa_siginfo)
old->sa_flags |= PosixSAFSigInfo;
if(oconf.sa_resethand)
old->sa_flags |= PosixSAFResetHandler;
if(oconf.sa_restart)
old->sa_flags |= PosixSAFRestart;
if(oconf.sa_nochildwait)
old->sa_flags |= PosixSAFNoChildrenWait;
} else {
old->sa_handler = oconf.handler;
old->sa_flags = 0;
old->sa_mask = 0;
}
}
return 0;
FailWithEINVAL:
*errnop = __libposix_get_errno(PosixEINVAL);
return -1;
} }

View File

@ -0,0 +1,49 @@
/*
* This file is part of Jehanne.
*
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3 of the License.
*
* Jehanne 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 General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
*/
#include <u.h>
#include <lib9.h>
#include <posix.h>
#include "internal.h"
int
POSIX_sigqueue(int *errnop, int pid, int signo, const union sigval value)
{
PosixError perror;
PosixSignalInfo siginfo;
int errno;
if(signo < 1 || signo > PosixNumberOfSignals){
*errnop = __libposix_get_errno(PosixEINVAL);
return -1;
}
memset(&siginfo, 0, sizeof(PosixSignalInfo));
siginfo.si_signo = signo;
siginfo.si_pid = *__libposix_pid;
siginfo.si_code = PosixSIQueue;
siginfo.si_uid = POSIX_getuid(&errno);
siginfo.si_value._sival_raw = value._sival_raw;
if(pid == siginfo.si_pid)
perror = __libposix_receive_signal(&siginfo);
else
perror = __libposix_dispatch_signal(pid, &siginfo);
if(perror != 0){
*errnop = __libposix_get_errno(perror);
return -1;
}
return 0;
}

292
sys/src/lib/posix/sigsets.c Normal file
View File

@ -0,0 +1,292 @@
/*
* This file is part of Jehanne.
*
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3 of the License.
*
* Jehanne 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 General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
*/
#include <u.h>
#include <lib9.h>
#include <posix.h>
#include "internal.h"
typedef union {
PosixSignalMask signals;
char raw[sizeof(PosixSignalMask)];
} SigSetBuf;
extern SignalConf *__libposix_signals;
extern int *__restart_syscall;
extern int *__libposix_devsignal;
PosixSignalMask *__libposix_signal_mask;
static PendingSignalList *__libposix_pending_signals;
static PendingSignalList **__libposix_pending_signals_end;
static int __libposix_blocked_signals;
void
__libposix_reset_pending_signals(void)
{
PendingSignalList *s;
while((s = __libposix_pending_signals) != nil){
__libposix_pending_signals = s->next;
free(s);
}
__libposix_pending_signals_end = &__libposix_pending_signals;
*__restart_syscall = 0;
*__libposix_signal_mask = 0;
}
int
__libposix_signal_blocked(PosixSignalInfo *siginfo)
{
PendingSignalList *l;
if((*__libposix_signal_mask & SIGNAL_MASK(siginfo->si_signo)) == 0)
return 0;
/* Blocked signals are recorded at __libposix_pending_signals
* and will be delivered by sigprocmask when they will
* be unblocked
*/
l = malloc(sizeof(PendingSignalList));
if(l == nil)
return 1; /* signal discarded */
memmove(&l->signal, siginfo, sizeof(PosixSignalInfo));
l->next = nil;
*__libposix_pending_signals_end = l;
__libposix_pending_signals_end = &l->next;
*__restart_syscall = 1;
++__libposix_blocked_signals;
return 1;
}
int
POSIX_sigaddset(int *errnop, PosixSignalMask *set, int signo)
{
if(signo < 1 || signo > PosixNumberOfSignals){
*errnop = __libposix_get_errno(PosixEINVAL);
return -1;
}
SIGNAL_RAW_ADD(*set, signo);
return 0;
}
int
POSIX_sigdelset(int *errnop, PosixSignalMask *set, int signo)
{
if(signo < 1 || signo > PosixNumberOfSignals){
*errnop = __libposix_get_errno(PosixEINVAL);
return -1;
}
SIGNAL_RAW_DEL(*set, signo);
return 0;
}
int
POSIX_sigismember(int *errnop, const PosixSignalMask *set, int signo)
{
if(signo < 1 || signo > PosixNumberOfSignals){
*errnop = __libposix_get_errno(PosixEINVAL);
return -1;
}
if(*set & SIGNAL_MASK(signo))
return 1;
return 0;
}
int
POSIX_sigfillset(int *errnop, PosixSignalMask *set)
{
*set = ~0;
return 0;
}
int
POSIX_sigemptyset(int *errnop, PosixSignalMask *set)
{
*set = 0;
return 0;
}
int
POSIX_sigpending(int *errnop, PosixSignalMask *set)
{
PendingSignalList *p;
PosixSignalMask tmp;
if(set == nil){
*errnop = __libposix_get_errno(PosixEFAULT);
return -1;
}
tmp = __libposix_sighelper_cmd(PHGetPendingSignals, 0);
/* include pending signals from outside the session */
p = __libposix_pending_signals;
while(p != nil){
tmp |= SIGNAL_MASK(p->signal.si_signo);
p = p->next;
}
*set = tmp;
return 0;
}
long
__libposix_sighelper_wait(PosixSignalMask set, PosixSignalInfo *siginfo)
{
return pread(*__libposix_devsignal, siginfo, sizeof(PosixSignalInfo), set);
}
int
POSIX_sigtimedwait(int *errnop, const PosixSignalMask *set,
PosixSignalInfo *info, const struct timespec *timeout)
{
long wkp = 0, r;
PendingSignalList *p, **end;
PosixSignalInfo tmp;
PosixError e = 0;
int ms = -1, bs;
if(set == nil){
e = PosixEFAULT;
goto FailWithError;
}
if(timeout != nil){
if(timeout->tv_sec < 0 || timeout->tv_nsec < 0){
e = PosixEINVAL;
goto FailWithError;
}
ms = timeout->tv_sec * 1000;
ms += timeout->tv_nsec / 1000000;
}
if(info == nil){
memset(&tmp, 0, sizeof(PosixSignalInfo));
info = &tmp;
}
LookupPendingSignals:
bs = __libposix_blocked_signals;
end = &__libposix_pending_signals;
for(p = *end; p != nil; p = *end){
if((*set & SIGNAL_MASK(p->signal.si_signo)) != 0){
memcpy(info, &p->signal, sizeof(PosixSignalInfo));
*end = p->next;
free(p);
if(__libposix_pending_signals == nil)
__libposix_pending_signals_end = &__libposix_pending_signals;
goto Done;
}
end = &p->next;
}
if(bs != __libposix_blocked_signals)
goto LookupPendingSignals;
if(ms == 0){
/* ms == 0 means that timeout has both fields to zero */
if(__libposix_sighelper_cmd(PHGetPendingSignals, 0) == 0){
e = PosixEAGAIN;
goto FailWithError;
}
}
if(ms > 0)
wkp = awake(ms);
r = __libposix_sighelper_wait(*set, info);
if(r < 0){
if(ms > 0 && awakened(wkp)){
/* timed out */
e = PosixEAGAIN;
goto FailWithError;
}
if(bs != __libposix_blocked_signals){
LookupPendingSignals2:
bs = __libposix_blocked_signals;
end = &__libposix_pending_signals;
for(p = *end; p != nil; p = *end){
if((*set & SIGNAL_MASK(p->signal.si_signo)) != 0){
memcpy(info, &p->signal, sizeof(PosixSignalInfo));
*end = p->next;
free(p);
if(__libposix_pending_signals == nil)
__libposix_pending_signals_end = &__libposix_pending_signals;
goto Done;
}
end = &p->next;
}
if(bs != __libposix_blocked_signals)
goto LookupPendingSignals2;
}
e = PosixEINTR;
goto FailWithError;
}
if(ms > 0)
forgivewkp(wkp);
Done:
return info->si_signo;
FailWithError:
*errnop = __libposix_get_errno(e);
return -1;
}
int
POSIX_sigprocmask(int *errnop, PosixSigProcMaskAction how, const PosixSignalMask *set, PosixSignalMask *oset)
{
PendingSignalList *p, **e;
PosixSignalMask new;
PosixSignalMask old = *__libposix_signal_mask;
int sigindex;
if(set){
new = *set;
new &= ~((255UL<<56) | (PosixSIGKILL-1) | (PosixSIGSTOP-1));
switch(how){
case PosixSPMSetMask:
*__libposix_signal_mask = new;
break;
case PosixSPMBlock:
*__libposix_signal_mask |= new;
break;
case PosixSPMUnblock:
*__libposix_signal_mask &= ~(new);
break;
default:
*errnop = __libposix_get_errno(PosixEINVAL);
return -1;
}
__libposix_sighelper_set(PHBlockSignals, *__libposix_signal_mask);
}
if(oset)
*oset = old;
new = *__libposix_signal_mask;
if(old & (~new)){
e = &__libposix_pending_signals;
for(p = *e; p != nil; p = *e){
sigindex = p->signal.si_signo - 1;
if((new & (1ULL << sigindex)) == 0){
__libposix_run_signal_handler(__libposix_signals + sigindex, &p->signal);
*e = p->next;
free(p);
} else {
e = &p->next;
}
}
}
return 0;
}

View File

@ -0,0 +1,46 @@
/*
* This file is part of Jehanne.
*
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3 of the License.
*
* Jehanne 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 General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
*/
#include <u.h>
#include <lib9.h>
#include <posix.h>
#include "internal.h"
int
POSIX_sigsuspend(int *errnop, const PosixSignalMask *mask)
{
PosixSignalMask old;
if(mask == nil){
*errnop = __libposix_get_errno(PosixEFAULT);
return -1;
}
if(POSIX_sigprocmask(errnop, PosixSPMSetMask, mask, &old) != 0)
return -1;
do
rendezvous((void*)~0, (void*)1);
while(__libposix_restart_syscall());
if(POSIX_sigprocmask(errnop, PosixSPMSetMask, &old, nil) != 0)
return -1;
*errnop = __libposix_get_errno(PosixEINTR);
return -1;
}

View File

@ -0,0 +1,62 @@
/*
* This file is part of Jehanne.
*
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3 of the License.
*
* Jehanne 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 General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
*/
#include <u.h>
#include <lib9.h>
#include <envvars.h>
#include <posix.h>
#include "internal.h"
int
POSIX_tcgetpgrp(int *errnop, int fd)
{
long pgrp;
if(!POSIX_isatty(errnop, fd))
return -1;
pgrp = __libposix_sighelper_cmd(PHGetForegroundGroup, 0);
if(pgrp <= 0)
goto FailWithENOTTY;
return pgrp;
FailWithENOTTY:
*errnop = __libposix_get_errno(PosixENOTTY);
return -1;
}
int
POSIX_tcsetpgrp(int *errnop, int fd, int pgrp)
{
PosixError e;
if(!POSIX_isatty(errnop, fd))
return -1;
if(pgrp < 0){
e = PosixEINVAL;
goto FailWithError;
}
if(__libposix_sighelper_cmd(PHSetForegroundGroup, pgrp) < 0){
e = PosixEPERM;
goto FailWithError;
}
return 0;
FailWithError:
*errnop = __libposix_get_errno(e);
return -1;
}

View File

@ -23,6 +23,13 @@
static PosixTimevalReader __libposix_timeval_reader; static PosixTimevalReader __libposix_timeval_reader;
static PosixTimezoneReader __libposix_timezone_reader; static PosixTimezoneReader __libposix_timezone_reader;
unsigned int
POSIX_alarm(int *errnop, unsigned int seconds)
{
long r = alarm(seconds * 1000);
return r/1000;
}
int int
POSIX_gettimeofday(int *errnop, void *timeval, void *timezone) POSIX_gettimeofday(int *errnop, void *timeval, void *timezone)
{ {