libposix: deep refactor; add sys/posixly command
With these changes, libposix (and newlib) can run MirBSD Korn Shell.
This commit is contained in:
parent
2f99fb162f
commit
001069aa7b
2
cfg/mksh/profile
Normal file
2
cfg/mksh/profile
Normal file
@ -0,0 +1,2 @@
|
||||
export PWD=`cat /dev/wdir`
|
||||
export HOSTNAME=$SYSNAME
|
5
qa/check
5
qa/check
@ -2,6 +2,11 @@
|
||||
|
||||
rfork
|
||||
|
||||
if( ! test -d /dev/posix ){
|
||||
sys/posixly -d /tmp/qa-posixly.log -p $PID &
|
||||
# sys/ctrace -o /tmp/posixly.trace $APID &
|
||||
}
|
||||
|
||||
dir=$1
|
||||
if(~ $dir '') dir=/qa
|
||||
|
||||
|
@ -74,7 +74,7 @@ main(void)
|
||||
elapsed = (nsec() - start) / (1000 * 1000);
|
||||
if(verbose)
|
||||
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");
|
||||
exits("FAIL");
|
||||
}
|
||||
@ -105,7 +105,7 @@ main(void)
|
||||
elapsed = (nsec() - start) / (1000 * 1000);
|
||||
if(verbose)
|
||||
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");
|
||||
exits("FAIL");
|
||||
}
|
||||
@ -113,8 +113,8 @@ main(void)
|
||||
|
||||
/* verify that tsemacquire are NOT interrupted */
|
||||
fprint(2, "verify that tsemacquire are NOT interrupted\n", elapsed);
|
||||
wkup = awake(700);
|
||||
start = nsec();
|
||||
wkup = awake(500);
|
||||
res = tsemacquire(&sem, 1500);
|
||||
elapsed = (nsec() - start) / (1000 * 1000);
|
||||
if(verbose)
|
||||
@ -137,7 +137,7 @@ main(void)
|
||||
elapsed = (nsec() - start) / (1000 * 1000);
|
||||
if(verbose)
|
||||
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");
|
||||
exits("FAIL");
|
||||
}
|
||||
@ -155,7 +155,7 @@ main(void)
|
||||
elapsed = (nsec() - start) / (1000 * 1000);
|
||||
if(verbose)
|
||||
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");
|
||||
exits("FAIL");
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ main(int argc, char* argv[])
|
||||
}
|
||||
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");
|
||||
exits("PASS");
|
||||
|
@ -112,7 +112,7 @@ waiter(int index)
|
||||
if(verbose)
|
||||
print("reader %d: got the rlock in %lld ms\n", getpid(), (end - start) / (1000*1000));
|
||||
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)));
|
||||
} else {
|
||||
if(verbose)
|
||||
@ -127,7 +127,7 @@ waiter(int index)
|
||||
rwakeup(&rCompleted);
|
||||
qunlock(&rl);
|
||||
|
||||
return (end - start) / (1000*1000) < 1300 ? nil : "FAIL";
|
||||
return (end - start) / (1000*1000) < 2000 ? nil : "FAIL";
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -214,7 +214,7 @@ main(int argc, char* argv[])
|
||||
}
|
||||
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");
|
||||
exits("PASS");
|
||||
|
@ -215,7 +215,7 @@ main(int argc, char* argv[])
|
||||
}
|
||||
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");
|
||||
exits("PASS");
|
||||
|
@ -210,7 +210,7 @@ main(int argc, char* argv[])
|
||||
}
|
||||
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");
|
||||
exits("PASS");
|
||||
|
7
qa/lib/newlib/001-hello.c
Normal file
7
qa/lib/newlib/001-hello.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
int main()
|
||||
{
|
||||
fprintf(stdout, "hello, stdout\n");
|
||||
fprintf(stderr, "hello, stderr\n");
|
||||
return 0;
|
||||
}
|
27
qa/lib/newlib/002-atexit.c
Normal file
27
qa/lib/newlib/002-atexit.c
Normal 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
44
qa/lib/newlib/041-env.c
Normal 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);
|
||||
}
|
32
qa/lib/newlib/041-env.runner
Normal file
32
qa/lib/newlib/041-env.runner
Normal 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
|
@ -11,43 +11,46 @@ main(int argc, char **argv)
|
||||
int p[2], ppgrp, opgrp, npgrp;
|
||||
char c = '?';
|
||||
|
||||
if (pipe(p) != 0)
|
||||
if (pipe(p) != 0){
|
||||
perror("pipe() error");
|
||||
else {
|
||||
ppgrp = getpgrp();
|
||||
printf("parent's pid %d; process group id %d\n", getpid(), ppgrp);
|
||||
if ((pid = fork()) == 0) {
|
||||
opgrp = getpgrp();
|
||||
printf("child's pid %d; process group id %d\n", getpid(), opgrp);
|
||||
write(p[1], &c, 1);
|
||||
setsid();
|
||||
npgrp = getpgrp();
|
||||
if(opgrp == npgrp){
|
||||
printf("FAIL: setsid did not changed child's process group id\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf("child's process group id is now %d\n", npgrp);
|
||||
sleep(5);
|
||||
exit(EXIT_SUCCESS);
|
||||
} else {
|
||||
read(p[0], &c, 1);
|
||||
sleep(3);
|
||||
if(ppgrp != getpgrp()){
|
||||
printf("FAIL: parent's process group id changed from %d to %d\n", ppgrp, getpgrp());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ppgrp = getpgrp();
|
||||
printf("parent's pid %d; process group id %d\n", getpid(), ppgrp);
|
||||
if ((pid = fork()) == 0) {
|
||||
opgrp = getpgrp();
|
||||
printf("child's pid %d; process group id %d\n", getpid(), opgrp);
|
||||
if(setsid() == -1){
|
||||
write(p[1], "e", 1);
|
||||
perror("FAIL: setsid");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
write(p[1], &c, 1);
|
||||
npgrp = getpgrp();
|
||||
if(opgrp == npgrp){
|
||||
printf("FAIL: setsid did not changed child's process group id\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf("child's process group id is now %d\n", npgrp);
|
||||
sleep(5);
|
||||
exit(EXIT_SUCCESS);
|
||||
} 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
|
||||
npgrp = getsid(pid);
|
||||
if(npgrp < 0){
|
||||
printf("FAIL: parent's getsid(%d) failed with errno %d\n", pid, errno);
|
||||
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
|
||||
npgrp = getsid(pid);
|
||||
if(npgrp == ppgrp){
|
||||
printf("FAIL: parent's getsid(%d) returned old process group id that should be changed\n", pid);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ test_output = /tmp/output-`{basename $test}
|
||||
|
||||
if ( test -e $test_output) rm $test_output
|
||||
|
||||
$test $test_output > /dev/null
|
||||
$test > $test_output
|
||||
if ( cat $test_output | grep 'FAIL' > /dev/null ) {
|
||||
cat $test_output
|
||||
echo FAIL
|
||||
|
48
qa/lib/newlib/120-fcntl.c
Normal file
48
qa/lib/newlib/120-fcntl.c
Normal 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
82
qa/lib/newlib/121-fcntl.c
Normal 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);
|
||||
}
|
@ -58,6 +58,7 @@ main() {
|
||||
signal(SIGQUIT, sigquit);
|
||||
|
||||
printf("\nChild going to loop...\n\n");
|
||||
write(p[1], "", 1);
|
||||
close(p[1]);
|
||||
close(p[0]);
|
||||
for(;;); /* loop for ever */
|
||||
@ -65,11 +66,11 @@ main() {
|
||||
else /* parent */
|
||||
{
|
||||
signal(SIGCHLD,sigchld);
|
||||
close(p[1]);
|
||||
if(read(p[0], &dummy, 1) > 0){
|
||||
printf("sync read received data");
|
||||
if(read(p[0], &dummy, 1) != 1){
|
||||
printf("sync read");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
close(p[1]);
|
||||
close(p[0]);
|
||||
printf("\nPARENT: sending SIGHUP\n\n");
|
||||
kill(pid,SIGHUP);
|
||||
|
@ -26,6 +26,7 @@ main() {
|
||||
|
||||
if (pid == 0) {
|
||||
printf("\nI am the new child!\n\n");
|
||||
write(p[1], "", 1);
|
||||
close(p[1]);
|
||||
close(p[0]);
|
||||
for(;;){
|
||||
@ -36,11 +37,11 @@ main() {
|
||||
}
|
||||
else /* parent */
|
||||
{
|
||||
close(p[1]);
|
||||
if(read(p[0], &dummy, 1) > 0){
|
||||
printf("sync read received data");
|
||||
if(read(p[0], &dummy, 1) != 1){
|
||||
printf("sync read");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
close(p[1]);
|
||||
close(p[0]);
|
||||
printf("\nPARENT: sending SIGINT\n\n");
|
||||
kill(pid,SIGINT);
|
||||
|
@ -28,6 +28,7 @@ main() {
|
||||
if (pid == 0) {
|
||||
signal(SIGCONT,sigcont); /* set function calls */
|
||||
printf("Child going to loop...\n");
|
||||
write(p[1], "", 1);
|
||||
close(p[1]);
|
||||
close(p[0]);
|
||||
for(;;){
|
||||
@ -38,11 +39,8 @@ main() {
|
||||
}
|
||||
else /* parent */
|
||||
{
|
||||
read(p[0], &dummy, 1);
|
||||
close(p[1]);
|
||||
if(read(p[0], &dummy, 1) > 0){
|
||||
printf("sync read received data");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
close(p[0]);
|
||||
printf("PARENT: sending SIGCONT\n\n");
|
||||
kill(pid,SIGCONT);
|
||||
|
@ -22,7 +22,8 @@ void childloop(void)
|
||||
{
|
||||
signal(SIGCONT,sigcont); /* 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[0]);
|
||||
for(;;){
|
||||
@ -54,11 +55,8 @@ main() {
|
||||
}
|
||||
else /* parent */
|
||||
{
|
||||
read(p[0], &dummy, 1);
|
||||
close(p[1]);
|
||||
if(read(p[0], &dummy, 1) > 0){
|
||||
printf("sync read received data");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
close(p[0]);
|
||||
sleep(2);
|
||||
printf("PARENT: sending SIGSTOP\n");
|
||||
|
@ -47,6 +47,7 @@ main() {
|
||||
signal(SIGQUIT, sigquit);
|
||||
|
||||
printf("Child going to loop...\n");
|
||||
write(p[1], "", 1);
|
||||
close(p[1]);
|
||||
close(p[0]);
|
||||
for(;;); /* loop for ever */
|
||||
@ -54,11 +55,8 @@ main() {
|
||||
else /* parent */
|
||||
{
|
||||
signal(SIGCHLD,sigchld);
|
||||
read(p[0], &dummy, 1);
|
||||
close(p[1]);
|
||||
if(read(p[0], &dummy, 1) > 0){
|
||||
printf("sync read received data");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
close(p[0]);
|
||||
printf("PARENT: sending SIGHUP\n");
|
||||
kill(pid,SIGHUP);
|
||||
|
51
qa/lib/newlib/206-signals.c
Normal file
51
qa/lib/newlib/206-signals.c
Normal 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;
|
||||
}
|
74
qa/lib/newlib/207-sigsuspend.c
Normal file
74
qa/lib/newlib/207-sigsuspend.c
Normal 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);
|
||||
}
|
69
qa/lib/newlib/208-sigpending.c
Normal file
69
qa/lib/newlib/208-sigpending.c
Normal 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;
|
||||
}
|
54
qa/lib/newlib/209-sigwaitinfo.c
Normal file
54
qa/lib/newlib/209-sigwaitinfo.c
Normal 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;
|
||||
}
|
58
qa/lib/newlib/210-sigtimedwait.c
Normal file
58
qa/lib/newlib/210-sigtimedwait.c
Normal 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;
|
||||
}
|
61
qa/lib/newlib/211-sigtimedwait.c
Normal file
61
qa/lib/newlib/211-sigtimedwait.c
Normal 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;
|
||||
}
|
54
qa/lib/newlib/212-sigwait.c
Normal file
54
qa/lib/newlib/212-sigwait.c
Normal 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;
|
||||
}
|
88
qa/lib/newlib/213-sigqueue.c
Normal file
88
qa/lib/newlib/213-sigqueue.c
Normal 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);
|
||||
}
|
132
qa/lib/newlib/214-sigsetjmp.c
Normal file
132
qa/lib/newlib/214-sigsetjmp.c
Normal 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;
|
||||
}
|
38
qa/lib/newlib/215-sigprocmask.c
Normal file
38
qa/lib/newlib/215-sigprocmask.c
Normal 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);
|
||||
}
|
||||
|
||||
}
|
@ -32,22 +32,37 @@
|
||||
],
|
||||
"SourceFilesCmd": [
|
||||
"000-hello.c",
|
||||
"001-hello.c",
|
||||
"002-atexit.c",
|
||||
"010-fork.c",
|
||||
"020-waitpid.c",
|
||||
"030-pause.c",
|
||||
"031-setjmp.c",
|
||||
"040-gettimeofday.c",
|
||||
"041-env.c",
|
||||
"050-setsid.c",
|
||||
"100-files.c",
|
||||
"101-files.c",
|
||||
"102-files.c",
|
||||
"103-files.c",
|
||||
"120-fcntl.c",
|
||||
"121-fcntl.c",
|
||||
"200-signals.c",
|
||||
"201-signals.c",
|
||||
"202-signals.c",
|
||||
"203-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": {
|
||||
@ -84,20 +99,37 @@
|
||||
],
|
||||
"SourceFilesCmd": [
|
||||
"000-hello.c",
|
||||
"001-hello.c",
|
||||
"002-atexit.c",
|
||||
"010-fork.c",
|
||||
"020-waitpid.c",
|
||||
"030-pause.c",
|
||||
"031-setjmp.c",
|
||||
"040-gettimeofday.c",
|
||||
"041-env.c",
|
||||
"050-setsid.c",
|
||||
"100-files.c",
|
||||
"101-files.c",
|
||||
"102-files.c",
|
||||
"103-files.c",
|
||||
"120-fcntl.c",
|
||||
"121-fcntl.c",
|
||||
"200-signals.c",
|
||||
"201-signals.c",
|
||||
"202-signals.c",
|
||||
"203-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": {
|
||||
|
@ -27,18 +27,34 @@ qa_exit_translator(int status)
|
||||
* should return PASS/FAIL
|
||||
*/
|
||||
if(status == 0){
|
||||
jehanne_print("PASS\n");
|
||||
return "PASS";
|
||||
} else {
|
||||
jehanne_print("FAIL: " __POSIX_EXIT_PREFIX "%d\n", status);
|
||||
return "FAIL";
|
||||
}
|
||||
}
|
||||
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
|
||||
__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);
|
||||
}
|
||||
|
@ -27,19 +27,35 @@ qa_exit_translator(int status)
|
||||
* should return PASS/FAIL
|
||||
*/
|
||||
if(status == 0){
|
||||
jehanne_print("PASS\n");
|
||||
return "PASS";
|
||||
} else {
|
||||
jehanne_print("FAIL: " __POSIX_EXIT_PREFIX "%d\n", status);
|
||||
return "FAIL";
|
||||
}
|
||||
}
|
||||
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
|
||||
__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_emulate_SIGCHLD();
|
||||
}
|
||||
|
@ -30,12 +30,18 @@
|
||||
* #include <u.h>
|
||||
* #include <posix.h>
|
||||
*
|
||||
* Defining _LIBPOSIX_H before the include allow you to just get dirent
|
||||
* definition.
|
||||
* Defining _LIBPOSIX_H before the include allow you to just get
|
||||
* data structure definition.
|
||||
*/
|
||||
|
||||
#ifndef _LIBPOSIX_DIRENT
|
||||
#define _LIBPOSIX_DIRENT
|
||||
#ifndef _LIBPOSIX_DEF
|
||||
#define _LIBPOSIX_DEF
|
||||
|
||||
struct timespec
|
||||
{
|
||||
long tv_sec;
|
||||
long tv_nsec;
|
||||
};
|
||||
|
||||
/* dirent alias of stat(5) message.
|
||||
* 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_WHT 14
|
||||
|
||||
#endif /* _LIBPOSIX_DIRENT */
|
||||
|
||||
#ifndef _LIBPOSIX_H
|
||||
#define _LIBPOSIX_H
|
||||
|
||||
typedef unsigned long clock_t;
|
||||
|
||||
/* getrusage who */
|
||||
typedef enum PosixRUsages
|
||||
{
|
||||
PosixRUsageSelf = 0,
|
||||
@ -90,10 +90,170 @@ typedef enum PosixRUsages
|
||||
PosixRUsageUnknown = -1
|
||||
} 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_SIGNAL_PREFIX "terminated by posix signal "
|
||||
#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_dup(int *errnop, int fildes);
|
||||
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 int POSIX_gettimeofday(int *errnop, void *timeval, void *timezone);
|
||||
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_malloc(int *errnop, 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 int POSIX_pipe(int *errnop, int fildes[2]);
|
||||
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_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_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 PosixError libposix_translate_kernel_errors(const char *msg);
|
||||
|
||||
/* 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
|
||||
*
|
||||
* 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_translate_error to translate error strings to PosixError
|
||||
* libposix_set_signal_trampoline to dispatch signal received as notes
|
||||
* libposix_set_stat_reader
|
||||
* libposix_set_tms_reader
|
||||
* libposix_set_timeval_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));
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Dispatch the signal to the registered handlers.
|
||||
/* Execute process disposition (executed when main returns)
|
||||
*/
|
||||
typedef enum PosixSignalAction
|
||||
{
|
||||
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);
|
||||
typedef void (*PosixProcessDisposer)(int status);
|
||||
|
||||
extern int libposix_on_process_disposition(PosixProcessDisposer dispose);
|
||||
|
||||
/* Enable SIGCHLD emulation
|
||||
*/
|
||||
|
@ -1,9 +1,13 @@
|
||||
{
|
||||
"disk": {
|
||||
"SystemTools": {
|
||||
"Include": [
|
||||
"../cmd.json"
|
||||
],
|
||||
"Install": "/arch/$ARCH/cmd/sys/",
|
||||
"Oflags": [
|
||||
"-static",
|
||||
"-lc"
|
||||
],
|
||||
"Projects": [
|
||||
"call/"
|
||||
],
|
||||
|
@ -22,11 +22,11 @@
|
||||
"/sys/src/lib/mp/",
|
||||
"/sys/src/lib/ndb/",
|
||||
"/sys/src/lib/plumb/",
|
||||
"/sys/src/lib/posix/",
|
||||
"/sys/src/lib/regexp/",
|
||||
"/sys/src/lib/sec/",
|
||||
"/sys/src/lib/stdio/",
|
||||
"/sys/src/lib/thread/"
|
||||
"/sys/src/lib/thread/",
|
||||
"/sys/src/lib/posix/"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"LibPosix": {
|
||||
"Cflags": [
|
||||
"-DARCH=\"$ARCH\"",
|
||||
"-fasm",
|
||||
"-I."
|
||||
],
|
||||
@ -12,16 +13,37 @@
|
||||
"SourceFiles": [
|
||||
"environment.c",
|
||||
"errors.c",
|
||||
"fcntl.c",
|
||||
"files.c",
|
||||
"ids.c",
|
||||
"initlib.c",
|
||||
"kill.c",
|
||||
"links.c",
|
||||
"memory.c",
|
||||
"others.c",
|
||||
"processes.c",
|
||||
"sigchlds.c",
|
||||
"signals.c",
|
||||
"sigqueue.c",
|
||||
"sigsets.c",
|
||||
"sigsuspend.c",
|
||||
"termios.c",
|
||||
"timers.c"
|
||||
]
|
||||
},
|
||||
"SignalHelper": {
|
||||
"Include": [
|
||||
"../../cmd/cmd.json"
|
||||
],
|
||||
"Install": "/arch/$ARCH/cmd/sys/",
|
||||
"Oflags": [
|
||||
"-static",
|
||||
"-lposix",
|
||||
"-l9p2000",
|
||||
"-lc"
|
||||
],
|
||||
"SourceFilesCmd": [
|
||||
"posixly.c"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -89,12 +89,96 @@ put_in_list(EnvVar* newenv)
|
||||
wunlock(&list_lock);
|
||||
}
|
||||
|
||||
char *
|
||||
POSIX_getenv(int *errno, const char *name)
|
||||
static int
|
||||
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;
|
||||
if(name == nil || name[0] == 0 || strchr(name, '=') == nil){
|
||||
*errno = PosixEINVAL;
|
||||
if(name == nil || name[0] == 0 || strchr(name, '=') != nil){
|
||||
*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;
|
||||
}
|
||||
|
||||
@ -110,12 +194,16 @@ POSIX_getenv(int *errno, const char *name)
|
||||
return e->value;
|
||||
|
||||
e = malloc(sizeof(EnvVar));
|
||||
if(e == nil){
|
||||
*errnop = PosixEINVAL;
|
||||
return nil;
|
||||
}
|
||||
e->next = nil;
|
||||
e->value = nil; // see free_env
|
||||
e->name = strdup(name);
|
||||
if(e->name == nil){
|
||||
free_env(e);
|
||||
*errno = PosixENOMEM;
|
||||
*errnop = PosixEINVAL;
|
||||
return nil;
|
||||
}
|
||||
e->value = getenv(name);
|
||||
|
@ -132,6 +132,39 @@ get_posix_error(PosixErrorMap *translations, char *err, uintptr_t caller)
|
||||
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
|
||||
__libposix_translate_errstr(uintptr_t caller)
|
||||
{
|
||||
@ -153,6 +186,8 @@ __libposix_translate_errstr(uintptr_t caller)
|
||||
perr = get_posix_error(handler->head, err, caller);
|
||||
if(perr == 0)
|
||||
perr = get_posix_error(generic_handlers, err, caller);
|
||||
if(perr == 0)
|
||||
perr = libposix_translate_kernel_errors(err);
|
||||
ret = __libposix_get_errno(perr);
|
||||
sys_errstr(err, ERRMAX);
|
||||
return ret;
|
||||
|
159
sys/src/lib/posix/fcntl.c
Normal file
159
sys/src/lib/posix/fcntl.c
Normal 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;
|
||||
}
|
@ -29,6 +29,10 @@ static int __libposix_R_OK;
|
||||
static int __libposix_W_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
|
||||
{
|
||||
SeekSet = 0,
|
||||
@ -48,6 +52,71 @@ __libposix_files_check_conf(void)
|
||||
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
|
||||
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 */
|
||||
|
||||
r = read(fd, buf, buf_bytes);
|
||||
if(r == 0)
|
||||
return 0;
|
||||
if(r < 0)
|
||||
goto FailWithENOENT; /* removed? */
|
||||
if(r < MINSTATLEN)
|
||||
|
@ -21,70 +21,83 @@
|
||||
#include <posix.h>
|
||||
#include "internal.h"
|
||||
|
||||
typedef union {
|
||||
int group;
|
||||
char raw[sizeof(int)];
|
||||
} IntBuf;
|
||||
|
||||
extern int *__libposix_devsignal;
|
||||
int __libposix_session_leader = -1;
|
||||
|
||||
static int
|
||||
get_noteid(int *errnop, int pid)
|
||||
get_ppid(int pid)
|
||||
{
|
||||
int n, f;
|
||||
char buf[30];
|
||||
sprint(buf, "/proc/%d/noteid", pid);
|
||||
f = open(buf, OREAD);
|
||||
if(f < 0){
|
||||
*errnop = __libposix_get_errno(PosixEPERM);
|
||||
long n;
|
||||
char buf[32];
|
||||
sprint(buf, "/proc/%d/ppid", pid);
|
||||
n = remove(buf);
|
||||
if(n == -1)
|
||||
return -1;
|
||||
}
|
||||
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 (int)n;
|
||||
}
|
||||
|
||||
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
|
||||
set_noteid(int *errnop, int pid, int noteid)
|
||||
set_group_id(int *errnop, int pid, int group)
|
||||
{
|
||||
int n, f;
|
||||
char buf[30];
|
||||
int mypid, ppid;
|
||||
|
||||
if(pid == 0)
|
||||
pid = getpid();
|
||||
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);
|
||||
if(pid < 0 || group < 0){
|
||||
*errnop = __libposix_get_errno(PosixEINVAL);
|
||||
return -1;
|
||||
}
|
||||
n = sprint(buf, "%d", noteid);
|
||||
n = write(f, buf, n);
|
||||
if(n < 0){
|
||||
if(pid == __libposix_session_leader){
|
||||
*errnop = __libposix_get_errno(PosixEPERM);
|
||||
return -1;
|
||||
}
|
||||
close(f);
|
||||
return 0;
|
||||
mypid = *__libposix_pid;
|
||||
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
|
||||
POSIX_getuid(int *errnop)
|
||||
{
|
||||
return 0;
|
||||
return 1000;
|
||||
}
|
||||
|
||||
int
|
||||
POSIX_geteuid(int *errnop)
|
||||
{
|
||||
return 0;
|
||||
return 1000;
|
||||
}
|
||||
|
||||
int
|
||||
@ -102,7 +115,7 @@ POSIX_seteuid(int *errnop, int euid)
|
||||
int
|
||||
POSIX_setreuid(int *errnop, int ruid, int euid)
|
||||
{
|
||||
return 0;
|
||||
return 1000;
|
||||
}
|
||||
|
||||
int
|
||||
@ -138,61 +151,129 @@ POSIX_setregid(int *errnop, int rgid, int egid)
|
||||
int
|
||||
POSIX_getpgrp(int *errnop)
|
||||
{
|
||||
int pid = getpid();
|
||||
return get_noteid(errnop, pid);
|
||||
long ret;
|
||||
int pid = *__libposix_pid;
|
||||
ret = __libposix_sighelper_cmd(PHGetProcessGroupId, pid);
|
||||
if(ret < 0)
|
||||
return pid;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
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
|
||||
POSIX_setpgid(int *errnop, int pid, int pgid)
|
||||
{
|
||||
if(pid < 0 || pgid < 0){
|
||||
*errnop = __libposix_get_errno(PosixEINVAL);
|
||||
return -1;
|
||||
}
|
||||
return set_noteid(errnop, pid, pgid);
|
||||
return set_group_id(errnop, pid, pgid);
|
||||
}
|
||||
|
||||
int
|
||||
POSIX_getsid(int *errnop, int pid)
|
||||
{
|
||||
int reqnoteid, mynoteid;
|
||||
int mypid;
|
||||
long sid;
|
||||
char buf[32];
|
||||
|
||||
if(pid < 0){
|
||||
FailWithESRCH:
|
||||
*errnop = __libposix_get_errno(PosixESRCH);
|
||||
return -1;
|
||||
}
|
||||
snprint(buf, sizeof(buf), "/proc/%d/ns", pid);
|
||||
if(access(buf, AEXIST) != 0)
|
||||
goto FailWithESRCH;
|
||||
|
||||
mypid = *__libposix_pid;
|
||||
if(pid == 0)
|
||||
pid = getpid();
|
||||
else if(pid == getpid())
|
||||
return __libposix_session_leader;
|
||||
reqnoteid = get_noteid(errnop, pid);
|
||||
if(reqnoteid < 0)
|
||||
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;
|
||||
pid = mypid;
|
||||
sid = __libposix_sighelper_cmd(PHGetSessionId, pid);
|
||||
if(sid < 0){
|
||||
*errnop = __libposix_get_errno(PosixEPERM);
|
||||
return -1;
|
||||
}
|
||||
return reqnoteid;
|
||||
if(pid == mypid)
|
||||
__libposix_session_leader = (int)sid;
|
||||
|
||||
return sid;
|
||||
}
|
||||
|
||||
int
|
||||
POSIX_setsid(int *errnop)
|
||||
{
|
||||
if(rfork(RFNAMEG|RFNOTEG) < 0){
|
||||
*errnop = __libposix_get_errno(PosixEPERM);
|
||||
return -1;
|
||||
extern PosixSignalMask *__libposix_signal_mask;
|
||||
extern SignalConf *__libposix_signals;
|
||||
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;
|
||||
}
|
||||
|
@ -24,11 +24,12 @@ extern int *__libposix_errors_codes;
|
||||
extern WaitList **__libposix_wait_list;
|
||||
extern ChildList **__libposix_child_list;
|
||||
static int __initialized;
|
||||
static unsigned char signals_to_code[256];
|
||||
static unsigned char code_to_signal[256];
|
||||
static PosixProcessDisposer __libposix_process_dispose;
|
||||
|
||||
|
||||
int *__libposix_sigchld_target_pid;
|
||||
int *__libposix_sigchld_father_pid;
|
||||
int *__libposix_sigchld_child_pid;
|
||||
int *__libposix_devsignal;
|
||||
int *__libposix_pid;
|
||||
|
||||
static void
|
||||
libposix_check_configuration(void)
|
||||
@ -36,32 +37,48 @@ libposix_check_configuration(void)
|
||||
__libposix_errors_check_conf();
|
||||
__libposix_files_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
|
||||
libposix_init(int argc, char *argv[], PosixInit init)
|
||||
{
|
||||
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 *__restart_syscall;
|
||||
extern int *__libposix_sigchld_target_pid;
|
||||
extern PosixSignalMask *__libposix_signal_mask;
|
||||
|
||||
WaitList *wait_list;
|
||||
ChildList *child_list;
|
||||
PosixSignalMask signal_mask;
|
||||
int mypid;
|
||||
int status;
|
||||
int error_codes[ERRNO_LAST-ERRNO_FIRST];
|
||||
int handling_signal;
|
||||
int sigchld_target_pid;
|
||||
int sigchld_father_pid;
|
||||
int sigchld_child_pid;
|
||||
int restart_syscall;
|
||||
int devsignal;
|
||||
|
||||
assert(__initialized == 0);
|
||||
|
||||
mypid = getpid();
|
||||
__libposix_pid = &mypid;
|
||||
|
||||
/* initialize PosixErrors map */
|
||||
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 */
|
||||
wait_list = nil;
|
||||
@ -72,28 +89,63 @@ libposix_init(int argc, char *argv[], PosixInit init)
|
||||
__libposix_child_list = &child_list;
|
||||
|
||||
/* initialize signal handling */
|
||||
restart_syscall = 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;
|
||||
__signals_to_code_map = signals_to_code;
|
||||
__code_to_signal_map = code_to_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))
|
||||
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();
|
||||
|
||||
__initialized = 1;
|
||||
status = main(argc, argv);
|
||||
|
||||
if(__libposix_process_dispose != nil)
|
||||
__libposix_process_dispose(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
|
||||
__libposix_initialized(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
@ -33,10 +33,29 @@ struct ChildList
|
||||
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_errors_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_get_errno(PosixError e);
|
||||
@ -51,16 +70,75 @@ extern void __libposix_free_wait_list(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 void __libposix_free_child_list(void);
|
||||
|
||||
extern void __libposix_forget_child(int pid);
|
||||
|
||||
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_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
50
sys/src/lib/posix/kill.c
Normal 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;
|
||||
}
|
@ -35,7 +35,8 @@ POSIX_isatty(int *errnop, int fd)
|
||||
}
|
||||
|
||||
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;
|
||||
*errnop = __libposix_get_errno(PosixENOTTY);
|
||||
return 0;
|
||||
@ -138,12 +139,14 @@ POSIX_getpass(int *errnop, const char *prompt)
|
||||
char *p;
|
||||
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;
|
||||
else if((r = open("/dev/cons", OREAD)) < 0)
|
||||
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;
|
||||
else if((w = open("/dev/cons", OWRITE)) < 0)
|
||||
goto CloseRAndReturnENXIO;
|
||||
|
1941
sys/src/lib/posix/posixly.c
Normal file
1941
sys/src/lib/posix/posixly.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -55,39 +55,29 @@ int (*__libposix_fork)(int *errnop) = fork_without_sigchld;
|
||||
void
|
||||
__libposix_free_wait_list(void)
|
||||
{
|
||||
WaitList *wl, *c;
|
||||
WaitList *tail, *w;
|
||||
|
||||
/* free the wait list as the memory is NOT shared */
|
||||
wl = *__libposix_wait_list;
|
||||
if(wl != nil){
|
||||
*__libposix_wait_list = nil;
|
||||
do
|
||||
{
|
||||
c = wl;
|
||||
wl = c->next;
|
||||
free(c);
|
||||
}
|
||||
while (wl != nil);
|
||||
tail = *__libposix_wait_list;
|
||||
while(w = tail){
|
||||
tail = tail->next;
|
||||
free(w);
|
||||
}
|
||||
*__libposix_wait_list = nil;
|
||||
}
|
||||
|
||||
void
|
||||
__libposix_free_child_list(void)
|
||||
{
|
||||
ChildList *l, *c;
|
||||
ChildList *tail, *c;
|
||||
|
||||
/* free the wait list as the memory is shared */
|
||||
l = *__libposix_child_list;
|
||||
if(l != nil){
|
||||
*__libposix_child_list = nil;
|
||||
do
|
||||
{
|
||||
c = l;
|
||||
l = c->next;
|
||||
free(c);
|
||||
}
|
||||
while (l != nil);
|
||||
tail = *__libposix_child_list;
|
||||
while(c = tail){
|
||||
tail = tail->next;
|
||||
free(c);
|
||||
}
|
||||
*__libposix_child_list = nil;
|
||||
}
|
||||
|
||||
int
|
||||
@ -112,8 +102,7 @@ __libposix_forget_child(int pid)
|
||||
|
||||
/* free the wait list as the memory is shared */
|
||||
l = __libposix_child_list;
|
||||
while(*l != nil){
|
||||
c = *l;
|
||||
while(c = *l){
|
||||
if(c->pid == pid){
|
||||
*l = c->next;
|
||||
free(c);
|
||||
@ -126,9 +115,18 @@ __libposix_forget_child(int pid)
|
||||
void
|
||||
__libposix_setup_new_process(void)
|
||||
{
|
||||
extern PosixSignalMask *__libposix_signal_mask;
|
||||
|
||||
*__libposix_pid = getpid();
|
||||
|
||||
/* reset wait list for the child */
|
||||
__libposix_free_wait_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
|
||||
@ -178,8 +176,6 @@ POSIX_getrusage(int *errnop, PosixRUsages who, void *r_usagep)
|
||||
int
|
||||
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
|
||||
if(env == environ){
|
||||
/* 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_close_on_exec();
|
||||
__libposix_sighelper_cmd(PHCallingExec, 0);
|
||||
|
||||
ret = sys_exec(name, argv);
|
||||
switch(ret){
|
||||
case 0:
|
||||
return 0;
|
||||
case ~0:
|
||||
*errnop = __libposix_translate_errstr((uintptr_t)POSIX_execve);
|
||||
break;
|
||||
default:
|
||||
*errnop = ret;
|
||||
break;
|
||||
}
|
||||
sys_exec(name, argv);
|
||||
*errnop = __libposix_translate_errstr((uintptr_t)POSIX_execve);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
POSIX_getpid(int *errnop)
|
||||
{
|
||||
return getpid();
|
||||
return *__libposix_pid;
|
||||
}
|
||||
|
||||
int
|
||||
@ -223,13 +212,14 @@ POSIX_fork(int *errnop)
|
||||
return __libposix_fork(errnop);
|
||||
}
|
||||
|
||||
int
|
||||
POSIX_wait(int *errnop, int *status)
|
||||
static int
|
||||
__libposix_wait(int *errnop, int *status, long ms)
|
||||
{
|
||||
Waitmsg *w;
|
||||
WaitList *l;
|
||||
char *s;
|
||||
char *s, err[ERRMAX];
|
||||
int ret = 0, sig = 0, pid;
|
||||
long wakeup = 0;
|
||||
|
||||
l = *__libposix_wait_list;
|
||||
if(l != nil){
|
||||
@ -242,10 +232,25 @@ POSIX_wait(int *errnop, int *status)
|
||||
}
|
||||
|
||||
OnIgnoredSignalInterrupt:
|
||||
if(ms)
|
||||
wakeup = awake(ms);
|
||||
w = wait();
|
||||
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;
|
||||
}
|
||||
if(wakeup){
|
||||
if(awakened(wakeup))
|
||||
return 0;
|
||||
forgivewkp(wakeup);
|
||||
}
|
||||
*errnop = __libposix_get_errno(PosixECHILD);
|
||||
return -1;
|
||||
}
|
||||
@ -283,13 +288,20 @@ POSIX_umask(int *errnop, int mask)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
POSIX_wait(int *errnop, int *status)
|
||||
{
|
||||
return __libposix_wait(errnop, status, 0);
|
||||
}
|
||||
|
||||
int
|
||||
POSIX_waitpid(int *errnop, int reqpid, int *status, int options)
|
||||
{
|
||||
Waitmsg *w;
|
||||
WaitList *c, **nl;
|
||||
char *s;
|
||||
int ret = 0, sig = 0, nohang = 0, pid;
|
||||
char *s, err[ERRMAX];
|
||||
int ret = 0, sig = 0, pid;
|
||||
long nohang = 0;
|
||||
|
||||
|
||||
if(options & __libposix_wnohang){
|
||||
@ -304,10 +316,9 @@ POSIX_waitpid(int *errnop, int reqpid, int *status, int options)
|
||||
switch(reqpid){
|
||||
case -1:
|
||||
if(nohang){
|
||||
*errnop = __libposix_get_errno(PosixEINVAL);
|
||||
return -1;
|
||||
return __libposix_wait(errnop, status, 100);
|
||||
}
|
||||
return POSIX_wait(errnop, status);
|
||||
return __libposix_wait(errnop, status, 0);
|
||||
case 0:
|
||||
/* not yet implemented; requires changes to Waitmsg */
|
||||
*errnop = __libposix_get_errno(PosixEINVAL);
|
||||
@ -337,13 +348,30 @@ POSIX_waitpid(int *errnop, int reqpid, int *status, int options)
|
||||
|
||||
WaitAgain:
|
||||
OnIgnoredSignalInterrupt:
|
||||
if(nohang)
|
||||
nohang = awake(100);
|
||||
w = wait();
|
||||
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;
|
||||
}
|
||||
if(nohang){
|
||||
if(awakened(nohang))
|
||||
return 0;
|
||||
forgivewkp(nohang);
|
||||
}
|
||||
*errnop = __libposix_get_errno(PosixECHILD);
|
||||
return -1;
|
||||
}
|
||||
if(nohang)
|
||||
forgivewkp(nohang);
|
||||
pid = w->pid;
|
||||
__libposix_forget_child(pid);
|
||||
if(w->msg[0] != 0){
|
||||
|
@ -21,61 +21,51 @@
|
||||
#include <posix.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 */
|
||||
extern int *__libposix_sigchld_target_pid;
|
||||
|
||||
#define CHILD_READY(pid) ((long)rendezvous(&__signals_to_code_map, (void*)(~(pid))))
|
||||
#define C2P_READY(pid) ((long)rendezvous(&__code_to_signal_map, (void*)(~(pid))))
|
||||
extern ChildList **__libposix_child_list;
|
||||
extern WaitList **__libposix_wait_list;
|
||||
extern SignalConf *__libposix_signals;
|
||||
extern int *__libposix_devsignal;
|
||||
|
||||
static void
|
||||
release_inherited_resources(void)
|
||||
open_sighelper_nanny(void)
|
||||
{
|
||||
notify(nil);
|
||||
rfork(RFCNAMEG|RFCENVG|RFNOTEG|RFCFDG);
|
||||
bind("#p", "/proc", MREPL);
|
||||
rfork(RFNOMNT);
|
||||
int mypid;
|
||||
if(*__libposix_devsignal >= 0)
|
||||
close(*__libposix_devsignal);
|
||||
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
|
||||
forwarding_note_handler(void *ureg, char *note)
|
||||
{
|
||||
extern int __min_known_sig;
|
||||
extern int __max_known_sig;
|
||||
int sig;
|
||||
PosixSignals signal;
|
||||
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);
|
||||
exit_on_SA_NOCLDWAIT(char *msg){
|
||||
/* we share the father's memory, we can inspect its configuration */
|
||||
if(__libposix_signals[PosixSIGCHLD-1].sa_nochildwait){
|
||||
/* the parent does not care about us*/
|
||||
rfork(RFNOWAIT);
|
||||
exits(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
forward_wait_msg(int sigchld_receiver, char *name)
|
||||
forward_wait_msg(int father, int child)
|
||||
{
|
||||
int n;
|
||||
char buf[512], err[ERRMAX], note[512], *fld[5];
|
||||
int n, mypid;
|
||||
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);
|
||||
write(n, name, strlen(name)+1);
|
||||
close(n);
|
||||
|
||||
rfork(RFCNAMEG|RFCENVG|RFNOMNT);
|
||||
|
||||
n = 0;
|
||||
WaitInterrupted:
|
||||
n = await(buf, sizeof buf-1);
|
||||
@ -84,21 +74,45 @@ WaitInterrupted:
|
||||
if(strstr(err, "no living children") == nil)
|
||||
goto WaitInterrupted;
|
||||
snprint(note, sizeof(note), "%s: %r", name);
|
||||
if(sigchld_receiver)
|
||||
postnote(PNPROC, sigchld_receiver, note);
|
||||
exit_on_SA_NOCLDWAIT(note);
|
||||
postnote(PNPROC, father, note);
|
||||
__libposix_sighelper_cmd(PHProcessExited, child);
|
||||
exits(note);
|
||||
}
|
||||
buf[n] = '\0';
|
||||
if(jehanne_tokenize(buf, fld, nelem(fld)) != nelem(fld)){
|
||||
snprint(note, sizeof(note), "%s: couldn't parse wait message", name);
|
||||
if(sigchld_receiver)
|
||||
postnote(PNPROC, sigchld_receiver, note);
|
||||
snprint(note, sizeof(note), "%s: can not parse wait msg: %s", name, buf);
|
||||
exit_on_SA_NOCLDWAIT(note);
|
||||
postnote(PNPROC, father, note);
|
||||
exits(note);
|
||||
}
|
||||
snprint(note, sizeof(note), __POSIX_SIGNAL_PREFIX " %d", __signals_to_code_map[PosixSIGCHLD]);
|
||||
if(sigchld_receiver){
|
||||
postnote(PNPROC, sigchld_receiver, note);
|
||||
}
|
||||
memset(&si, 0, sizeof(PosixSignalInfo));
|
||||
si.si_pid = mypid;
|
||||
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]);
|
||||
}
|
||||
|
||||
@ -106,99 +120,76 @@ WaitInterrupted:
|
||||
static int
|
||||
fork_with_sigchld(int *errnop)
|
||||
{
|
||||
int father = getpid();
|
||||
int p2c;
|
||||
long c2p = -1, child = -1;
|
||||
char proxy_name[256];
|
||||
int proxy, father, child = -1;
|
||||
ChildList *c;
|
||||
uint64_t rend;
|
||||
char *buf;
|
||||
|
||||
/* Father here:
|
||||
* - create P2C
|
||||
* - wait for C2P to be ready
|
||||
* - register P2C in children list
|
||||
* - return P2C pid
|
||||
* - create proxy
|
||||
* - wait for child to be ready
|
||||
* - register proxy in children list
|
||||
* - return proxy pid
|
||||
*/
|
||||
switch(p2c = rfork(RFPROC|RFMEM)){
|
||||
father = getpid();
|
||||
|
||||
switch(proxy = rfork(RFPROC|RFMEM|RFFDG)){
|
||||
case -1:
|
||||
return -1;
|
||||
case 0:
|
||||
/* P2C here:
|
||||
* - create C2P
|
||||
* - wait for the child pid
|
||||
* - release all inherited resources
|
||||
* - install forwarding_note_handler
|
||||
* - send to father the C2P pid
|
||||
* - start waiting for the child
|
||||
/* proxy here:
|
||||
* - create child
|
||||
* - start waiting
|
||||
*/
|
||||
switch(c2p = rfork(RFPROC|RFMEM)){
|
||||
*__libposix_pid = getpid();
|
||||
open_sighelper_nanny();
|
||||
switch(child = rfork(RFPROC|RFFDG)){
|
||||
case -1:
|
||||
while(C2P_READY(-2) == -1)
|
||||
;
|
||||
exits("rfork (c2p)");
|
||||
rend = *__libposix_pid;
|
||||
while(rendezvous((void*)rend, "e") == (void*)-1)
|
||||
sleep(100);
|
||||
rfork(RFNOWAIT);
|
||||
exits("rfork (child)");
|
||||
case 0:
|
||||
/* C2P 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
|
||||
/* Beloved child here
|
||||
*/
|
||||
switch(child = fork()){
|
||||
case -1:
|
||||
while(CHILD_READY(-2) == -1)
|
||||
;
|
||||
exits("rfork (child)");
|
||||
case 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);
|
||||
}
|
||||
__libposix_setup_new_process();
|
||||
rend = *__libposix_pid;
|
||||
while(rendezvous((void*)rend, "d") == (void*)-1)
|
||||
sleep(100);
|
||||
rfork(RFREND);
|
||||
return 0;
|
||||
default:
|
||||
while((child = CHILD_READY(-3)) == -1)
|
||||
;
|
||||
child = ~child;
|
||||
if(child < 0){
|
||||
while(C2P_READY(-2) == -1)
|
||||
;
|
||||
waitpid();
|
||||
exits("rfork (child)");
|
||||
}
|
||||
release_inherited_resources();
|
||||
*__libposix_sigchld_target_pid = child;
|
||||
notify(forwarding_note_handler);
|
||||
snprint(proxy_name, sizeof(proxy_name), "libposix signal proxy %d > %d", father, child);
|
||||
while(C2P_READY(c2p) == -1)
|
||||
;
|
||||
forward_wait_msg(0, proxy_name);
|
||||
rend = child;
|
||||
while((buf = rendezvous((void*)rend, "")) == (void*)-1)
|
||||
sleep(100);
|
||||
rend = *__libposix_pid;
|
||||
while(rendezvous((void*)rend, "d") == (void*)-1)
|
||||
sleep(100);
|
||||
|
||||
/* we share the memory of the parent but we do
|
||||
* not need these that fortunately are on the private stack
|
||||
*/
|
||||
*__libposix_wait_list = nil;
|
||||
*__libposix_child_list = nil;
|
||||
forward_wait_msg(father, child);
|
||||
}
|
||||
default:
|
||||
while((c2p = C2P_READY(-3)) == -1)
|
||||
;
|
||||
c2p = ~c2p;
|
||||
if(c2p < 0){
|
||||
waitpid();
|
||||
rend = proxy;
|
||||
while((buf = rendezvous((void*)rend, "")) == (void*)-1)
|
||||
sleep(100);
|
||||
if(buf[0] == 'e')
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* no need to lock: the child list is private */
|
||||
c = malloc(sizeof(ChildList));
|
||||
c->pid = p2c;
|
||||
c->pid = proxy;
|
||||
c->next = *__libposix_child_list;
|
||||
*__libposix_child_list = c;
|
||||
|
||||
return p2c;
|
||||
return proxy;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -19,22 +19,25 @@
|
||||
/* POSIX signals have weird semantics that are hard to emulate in a
|
||||
* sane system without giving up on its sanity.
|
||||
*
|
||||
* We distinguish control signals (SIGKILL, SIGSTOP, SIGCONT,
|
||||
* SIGABRT, SIGIOT), SIGCHLD/SIGCLD, timers' wakeups
|
||||
* We distinguish control signals (SIGKILL, SIGSTOP, SIGTSTP, SIGCONT,
|
||||
* SIGABRT, SIGTTIN, SIGTTOU, SIGIOT), SIGCHLD/SIGCLD, timers' wakeups
|
||||
* (SIGALRM, SIGPROF, SIGVTALRM) and all the others.
|
||||
*
|
||||
* TRASMISSION
|
||||
* -----------
|
||||
* Signal transmission depends on the relation between the sender
|
||||
* and the receiver:
|
||||
* 1) if sender and receiver have no relation the signal is translated
|
||||
* to a note and sent to the receiver(s);
|
||||
* 2) if sender == receiver the signal trampoline is directly invoked
|
||||
* for all signals except control ones and the default disposition occurs if
|
||||
* the trampoline does not handle the signal
|
||||
* 3) if sender is parent or child of receiver the transmision
|
||||
* differs from the default if libposix_emulate_SIGCHLD() has been
|
||||
* called during library initialization
|
||||
* Signal transmission is done though a file server mounted /dev/posix/,
|
||||
* provided by sys/posixly. On startup and at each fork, processes
|
||||
* create a file named /dev/posix/signal with ORDWR mode and perm
|
||||
* equals to their pid. Writing and Reading such file they can
|
||||
* control signal dispatching, process groups and so on.
|
||||
*
|
||||
* When a signal is written to /dev/posix/signal, it is translated for
|
||||
* each receiver to a note, and written to the specific note file.
|
||||
*
|
||||
* 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
|
||||
* 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:
|
||||
* - 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
|
||||
* the current process
|
||||
* - SIGCONT => invoke the registered signal handlers via the signal
|
||||
* trampoline and continue; note that (since a stopped
|
||||
* process cannot resume itself) the sender will write
|
||||
* "start" to the control file of the receiver before
|
||||
* sending the note (unless SIGCHLD emulation is enable).
|
||||
* process cannot resume itself) sys/posixly will write
|
||||
* "start" to the control file of the receiver.
|
||||
*
|
||||
* SIGCHLD/SIGCLD
|
||||
* --------------
|
||||
@ -72,30 +76,26 @@
|
||||
*
|
||||
* Such emulation changes the way POSIX_fork and POSIX_kill works.
|
||||
*
|
||||
* Each fork() will spawn two additional processes that are designed
|
||||
* to proxy signals between the parent and the desired child:
|
||||
* Each fork() will spawn an additional process that share the memory
|
||||
* of the parent, and waits for the child, so that it can send SIGCHLD:
|
||||
*
|
||||
* parent
|
||||
* +- proxy from parent to child (P2C)
|
||||
* +- proxy from child to parent (C2P)
|
||||
* +- child
|
||||
* +- nanny
|
||||
* +- 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.
|
||||
*
|
||||
* When the child exits, C2P will send a SIGCHLD note to parent and
|
||||
* then exit with the same status. Then P2C will exit with
|
||||
* the same status too.
|
||||
* When the child exits, the proxy will send a SIGCHLD sigchld to parent
|
||||
* and then exit with the same status.
|
||||
*
|
||||
* As the parent process will see P2C as its child, it will send any
|
||||
* signal to it via kill 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.
|
||||
* As the parent process will see the proxy as its child, it will send
|
||||
* any signal to it via kill or sigqueue and will wait it on SIGCHLD.
|
||||
*
|
||||
* TIMERS
|
||||
* ------
|
||||
@ -104,6 +104,7 @@
|
||||
* expire in a signal handler (interrupting a blocking syscall) but
|
||||
* without giving up the simplicity of notes.
|
||||
*
|
||||
* (TO BE IMPLEMENTED: )
|
||||
* We allocate these timers on libposix initialization. When normal
|
||||
* code is running timers will be implemented via Jehanne's alarms,
|
||||
* producing a note on expiration that will be mapped to the proper
|
||||
@ -122,16 +123,22 @@
|
||||
#include <posix.h>
|
||||
#include "internal.h"
|
||||
|
||||
unsigned char *__signals_to_code_map;
|
||||
unsigned char *__code_to_signal_map;
|
||||
int *__handling_external_signal;
|
||||
int *__restart_syscall;
|
||||
extern PosixSignalMask *__libposix_signal_mask;
|
||||
extern int *__libposix_devsignal;
|
||||
|
||||
static int __sigrtmin;
|
||||
static int __sigrtmax;
|
||||
int __min_known_sig;
|
||||
int __max_known_sig;
|
||||
static PosixSignalTrampoline __libposix_signal_trampoline;
|
||||
typedef union {
|
||||
PosixSignalInfo signal;
|
||||
char raw[sizeof(PosixSignalInfo)];
|
||||
} SignalBuf;
|
||||
typedef union {
|
||||
PosixSignalMask signals;
|
||||
char raw[sizeof(PosixSignalMask)];
|
||||
} SigSetBuf;
|
||||
|
||||
static SignalConf signal_configurations[PosixNumberOfSignals];
|
||||
SignalConf *__libposix_signals = signal_configurations;
|
||||
|
||||
typedef enum PosixSignalDisposition
|
||||
{
|
||||
@ -143,23 +150,37 @@ typedef enum PosixSignalDisposition
|
||||
} PosixSignalDisposition;
|
||||
|
||||
static PosixError
|
||||
note_all_writable_processes(int sig)
|
||||
note_all_writable_processes(PosixSignalInfo* siginfo)
|
||||
{
|
||||
// TODO: loop over writable note files and post note.
|
||||
return PosixEPERM;
|
||||
}
|
||||
|
||||
static void
|
||||
terminated_by_signal(int sig)
|
||||
terminated_by_signal(int signo)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
__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);
|
||||
}
|
||||
|
||||
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
|
||||
__libposix_send_control_msg(int pid, char *msg)
|
||||
{
|
||||
@ -189,7 +210,7 @@ ErrorBeforeOpen:
|
||||
/* Executes a PosixSignalDisposition.
|
||||
*/
|
||||
static int
|
||||
execute_disposition(int sig, PosixSignalDisposition action)
|
||||
execute_disposition(int signo, PosixSignalDisposition action)
|
||||
{
|
||||
int aborted_by_signal;
|
||||
|
||||
@ -199,32 +220,27 @@ execute_disposition(int sig, PosixSignalDisposition action)
|
||||
*__restart_syscall = 1;
|
||||
return 1;
|
||||
case TerminateTheProcess:
|
||||
terminated_by_signal(sig);
|
||||
terminated_by_signal(signo);
|
||||
break;
|
||||
case TerminateTheProcessAndCoreDump:
|
||||
aborted_by_signal = 0;
|
||||
assert(aborted_by_signal);
|
||||
break;
|
||||
case StopTheProcess:
|
||||
return __libposix_send_control_msg(getpid(), "stop");
|
||||
return __libposix_send_control_msg(*__libposix_pid, "stop");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PosixSignalDisposition
|
||||
default_signal_disposition(int code)
|
||||
default_signal_disposition(PosixSignals signal)
|
||||
{
|
||||
PosixSignals signal;
|
||||
|
||||
// see http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html
|
||||
if(__sigrtmin != 0 && __sigrtmax != 0
|
||||
&&(code >= __sigrtmin || code <= __sigrtmax))
|
||||
if(signal >= PosixSIGRTMIN && signal <= PosixSIGRTMAX)
|
||||
return TerminateTheProcess;
|
||||
|
||||
signal = __code_to_signal_map[code];
|
||||
switch(signal){
|
||||
default:
|
||||
sysfatal("libposix: undefined signal %d", code);
|
||||
sysfatal("libposix: undefined signal %d", signal);
|
||||
|
||||
case PosixSIGALRM:
|
||||
case PosixSIGHUP:
|
||||
@ -255,7 +271,6 @@ default_signal_disposition(int code)
|
||||
case PosixSIGXFSZ:
|
||||
return TerminateTheProcessAndCoreDump;
|
||||
case PosixSIGCHLD:
|
||||
case PosixSIGCLD:
|
||||
case PosixSIGURG:
|
||||
return IgnoreWithNoEffect;
|
||||
case PosixSIGCONT:
|
||||
@ -263,209 +278,360 @@ default_signal_disposition(int code)
|
||||
}
|
||||
}
|
||||
|
||||
PosixError
|
||||
__libposix_receive_signal(int sig)
|
||||
/* returns 1 if the signal handling has been completed, 0 otherwise */
|
||||
int
|
||||
__libposix_run_signal_handler(SignalConf *c, PosixSignalInfo *siginfo)
|
||||
{
|
||||
PosixSignalAction action = SignalDefault;
|
||||
PosixSignals psig = __code_to_signal_map[sig];
|
||||
PosixSignalDisposition disposition;
|
||||
PosixSigHandler h;
|
||||
PosixSigAction a;
|
||||
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){
|
||||
case SignalCatched:
|
||||
switch((uintptr_t)c->handler){
|
||||
case 0:
|
||||
/* SIG_DFL */
|
||||
if(c->sa_restart)
|
||||
*__restart_syscall = 1;
|
||||
break;
|
||||
case SignalIgnored:
|
||||
case 1:
|
||||
/* SIG_IGN */
|
||||
if(siginfo->si_signo == PosixSIGABRT)
|
||||
break;
|
||||
*__restart_syscall = 1;
|
||||
break;
|
||||
case SignalDefault:
|
||||
disposition = default_signal_disposition(sig);
|
||||
if(!execute_disposition(sig, disposition))
|
||||
return PosixEPERM;
|
||||
break;
|
||||
case SignalError:
|
||||
return PosixEINVAL;
|
||||
return 1;
|
||||
default:
|
||||
m = *__libposix_signal_mask;
|
||||
*__libposix_signal_mask |= c->mask;
|
||||
__libposix_sighelper_set(PHBlockSignals, *__libposix_signal_mask);
|
||||
a = c->handler;
|
||||
h = c->handler;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
PosixError
|
||||
__libposix_notify_signal_to_process(int pid, int signal)
|
||||
__libposix_receive_signal(PosixSignalInfo *siginfo)
|
||||
{
|
||||
char buf[128];
|
||||
int fd, n;
|
||||
SignalConf *c;
|
||||
PosixSignalDisposition disposition;
|
||||
PosixSignals signo = siginfo->si_signo;
|
||||
|
||||
snprint(buf, sizeof(buf), "/proc/%d/note", pid);
|
||||
if((fd = open(buf, OWRITE)) < 0){
|
||||
if(access(buf, AEXIST) == 0)
|
||||
return PosixEPERM;
|
||||
else
|
||||
return PosixESRCH;
|
||||
}
|
||||
n = snprint(buf, sizeof(buf), __POSIX_SIGNAL_PREFIX "%d", signal);
|
||||
write(fd, buf, n);
|
||||
close(fd);
|
||||
if(signo == PosixSIGKILL || signo == PosixSIGSTOP)
|
||||
goto ExecuteDefaultDisposition;
|
||||
|
||||
if(__libposix_signal_blocked(siginfo))
|
||||
return 0;
|
||||
|
||||
c = __libposix_signals + (signo-1);
|
||||
if(__libposix_run_signal_handler(c, siginfo))
|
||||
return 0;
|
||||
|
||||
ExecuteDefaultDisposition:
|
||||
disposition = default_signal_disposition(signo);
|
||||
if(!execute_disposition(signo, disposition))
|
||||
return PosixEPERM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PosixError
|
||||
notify_signal_to_group(int pid, int signal)
|
||||
long
|
||||
__libposix_sighelper_signal(PosixHelperCommand command, int posix_process_pid, PosixSignalInfo *siginfo)
|
||||
{
|
||||
char buf[128];
|
||||
int fd, n;
|
||||
union {
|
||||
PosixHelperRequest request;
|
||||
long raw;
|
||||
} offset;
|
||||
char buf[sizeof(PosixSignalInfo)];
|
||||
|
||||
snprint(buf, sizeof(buf), "/proc/%d/notepg", pid);
|
||||
if((fd = open(buf, OWRITE)) < 0){
|
||||
if(access(buf, AEXIST) == 0)
|
||||
return PosixEPERM;
|
||||
else
|
||||
return PosixESRCH;
|
||||
}
|
||||
n = snprint(buf, sizeof(buf), __POSIX_SIGNAL_PREFIX "%d", signal);
|
||||
write(fd, buf, n);
|
||||
close(fd);
|
||||
return 0;
|
||||
offset.request.command = command;
|
||||
offset.request.target = posix_process_pid;
|
||||
|
||||
memcpy(buf, siginfo, sizeof(buf));
|
||||
|
||||
return pwrite(*__libposix_devsignal, buf, sizeof(buf), offset.raw);
|
||||
}
|
||||
|
||||
long
|
||||
__libposix_sighelper_set(PosixHelperCommand command, PosixSignalMask signal_set)
|
||||
{
|
||||
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
|
||||
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;
|
||||
switch(pid){
|
||||
case 0:
|
||||
return notify_signal_to_group(getpid(), sig);
|
||||
return notify_signal_to_group(*__libposix_pid, siginfo);
|
||||
case -1:
|
||||
return note_all_writable_processes(sig);
|
||||
return note_all_writable_processes(siginfo);
|
||||
default:
|
||||
if(pid < 0)
|
||||
return notify_signal_to_group(-pid, sig);
|
||||
return notify_signal_to_group(-pid, siginfo);
|
||||
break;
|
||||
}
|
||||
signal = __code_to_signal_map[sig];
|
||||
error = __libposix_notify_signal_to_process(pid, sig);
|
||||
if(signal == PosixSIGCONT && !__libposix_is_child(pid))
|
||||
error = __libposix_notify_signal_to_process(pid, siginfo);
|
||||
if(siginfo->si_signo == PosixSIGCONT && !__libposix_is_child(pid))
|
||||
__libposix_send_control_msg(pid, "start");
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
POSIX_kill(int *errnop, int pid, int sig)
|
||||
static int
|
||||
translate_jehanne_kernel_note(const char *note, PosixSignalInfo *siginfo)
|
||||
{
|
||||
PosixSignals signal;
|
||||
PosixError perror;
|
||||
char *trap[3];
|
||||
char *tmp;
|
||||
|
||||
signal = __code_to_signal_map[sig];
|
||||
if(signal == 0
|
||||
&&(__sigrtmin != 0 && __sigrtmax != 0)
|
||||
&&(sig < __sigrtmin || sig > __sigrtmax))
|
||||
sysfatal("libposix: undefined signal %d", sig);
|
||||
if(pid == getpid())
|
||||
perror = __libposix_receive_signal(sig);
|
||||
else
|
||||
perror = dispatch_signal(pid, sig);
|
||||
if(perror != 0){
|
||||
*errnop = __libposix_get_errno(perror);
|
||||
return -1;
|
||||
assert(siginfo->si_signo == 0);
|
||||
|
||||
if(strncmp("trap: fault ", note, 12) == 0){
|
||||
// trap: fault read addr=0x0 pc=0x400269
|
||||
note += 12;
|
||||
siginfo->si_signo = PosixSIGTRAP;
|
||||
tmp = strdup(note);
|
||||
if(getfields(tmp, trap, 3, 1, " ") == 3){
|
||||
if(trap[0][0] == 'r')
|
||||
siginfo->si_code = PosixSIFaultMapError;
|
||||
else
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
__libposix_note_handler(void *ureg, char *note)
|
||||
{
|
||||
int sig;
|
||||
PosixSignalInfo siginfo;
|
||||
PosixError error;
|
||||
if(strncmp(note, __POSIX_SIGNAL_PREFIX, __POSIX_SIGNAL_PREFIX_LEN) != 0)
|
||||
return translate_jehanne_note(note); // TODO: should we translate common notes?
|
||||
sig = __libposix_note_to_signal(note);
|
||||
if(sig < __min_known_sig || sig > __max_known_sig)
|
||||
|
||||
memset(&siginfo, 0, sizeof(PosixSignalInfo));
|
||||
|
||||
if(!__libposix_note_to_signal(note, &siginfo)
|
||||
&& (siginfo.si_signo < 1 || siginfo.si_signo > PosixNumberOfSignals))
|
||||
sysfatal("libposix: '%s' does not carry a signal", note);
|
||||
*__handling_external_signal = 1;
|
||||
error = __libposix_receive_signal(sig);
|
||||
error = __libposix_receive_signal(&siginfo);
|
||||
*__handling_external_signal = 0;
|
||||
werrstr("interrupted");
|
||||
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
|
||||
__libposix_restart_syscall(void)
|
||||
{
|
||||
int r = *__restart_syscall;
|
||||
int r;
|
||||
|
||||
if(*__handling_external_signal)
|
||||
return 0;
|
||||
|
||||
r = *__restart_syscall;
|
||||
*__restart_syscall = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
__libposix_signal_check_conf(void)
|
||||
int
|
||||
POSIX_sigaction(int *errnop, int signo, const struct sigaction *act, struct sigaction *old)
|
||||
{
|
||||
if(__libposix_signal_trampoline == nil)
|
||||
sysfatal("libposix: no signal trampoline");
|
||||
SignalConf *c, oconf;
|
||||
|
||||
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;
|
||||
}
|
||||
|
49
sys/src/lib/posix/sigqueue.c
Normal file
49
sys/src/lib/posix/sigqueue.c
Normal 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
292
sys/src/lib/posix/sigsets.c
Normal 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;
|
||||
}
|
46
sys/src/lib/posix/sigsuspend.c
Normal file
46
sys/src/lib/posix/sigsuspend.c
Normal 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;
|
||||
}
|
62
sys/src/lib/posix/termios.c
Normal file
62
sys/src/lib/posix/termios.c
Normal 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;
|
||||
}
|
@ -23,6 +23,13 @@
|
||||
static PosixTimevalReader __libposix_timeval_reader;
|
||||
static PosixTimezoneReader __libposix_timezone_reader;
|
||||
|
||||
unsigned int
|
||||
POSIX_alarm(int *errnop, unsigned int seconds)
|
||||
{
|
||||
long r = alarm(seconds * 1000);
|
||||
return r/1000;
|
||||
}
|
||||
|
||||
int
|
||||
POSIX_gettimeofday(int *errnop, void *timeval, void *timezone)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user