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
|
@ -0,0 +1,2 @@
|
||||||
|
export PWD=`cat /dev/wdir`
|
||||||
|
export HOSTNAME=$SYSNAME
|
5
qa/check
5
qa/check
|
@ -2,6 +2,11 @@
|
||||||
|
|
||||||
rfork
|
rfork
|
||||||
|
|
||||||
|
if( ! test -d /dev/posix ){
|
||||||
|
sys/posixly -d /tmp/qa-posixly.log -p $PID &
|
||||||
|
# sys/ctrace -o /tmp/posixly.trace $APID &
|
||||||
|
}
|
||||||
|
|
||||||
dir=$1
|
dir=$1
|
||||||
if(~ $dir '') dir=/qa
|
if(~ $dir '') dir=/qa
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ main(void)
|
||||||
elapsed = (nsec() - start) / (1000 * 1000);
|
elapsed = (nsec() - start) / (1000 * 1000);
|
||||||
if(verbose)
|
if(verbose)
|
||||||
fprint(2, "rendezvous interrupted, returned %#p, elapsed = %d ms\n", res, elapsed);
|
fprint(2, "rendezvous interrupted, returned %#p, elapsed = %d ms\n", res, elapsed);
|
||||||
if(!awakened(wkup) || elapsed < 900 || elapsed > 1300){
|
if(!awakened(wkup) || elapsed < 900 || elapsed > 1800){
|
||||||
print("FAIL: rendezvous\n");
|
print("FAIL: rendezvous\n");
|
||||||
exits("FAIL");
|
exits("FAIL");
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ main(void)
|
||||||
elapsed = (nsec() - start) / (1000 * 1000);
|
elapsed = (nsec() - start) / (1000 * 1000);
|
||||||
if(verbose)
|
if(verbose)
|
||||||
print("semacquire(&sem, 1): returned %lld, elapsed = %d ms\n", res, elapsed);
|
print("semacquire(&sem, 1): returned %lld, elapsed = %d ms\n", res, elapsed);
|
||||||
if(!awakened(wkup) || res != -1 || elapsed < 900 || elapsed > 1300){
|
if(!awakened(wkup) || res != -1 || elapsed < 900 || elapsed > 1800){
|
||||||
print("FAIL: semacquire\n");
|
print("FAIL: semacquire\n");
|
||||||
exits("FAIL");
|
exits("FAIL");
|
||||||
}
|
}
|
||||||
|
@ -113,8 +113,8 @@ main(void)
|
||||||
|
|
||||||
/* verify that tsemacquire are NOT interrupted */
|
/* verify that tsemacquire are NOT interrupted */
|
||||||
fprint(2, "verify that tsemacquire are NOT interrupted\n", elapsed);
|
fprint(2, "verify that tsemacquire are NOT interrupted\n", elapsed);
|
||||||
wkup = awake(700);
|
|
||||||
start = nsec();
|
start = nsec();
|
||||||
|
wkup = awake(500);
|
||||||
res = tsemacquire(&sem, 1500);
|
res = tsemacquire(&sem, 1500);
|
||||||
elapsed = (nsec() - start) / (1000 * 1000);
|
elapsed = (nsec() - start) / (1000 * 1000);
|
||||||
if(verbose)
|
if(verbose)
|
||||||
|
@ -137,7 +137,7 @@ main(void)
|
||||||
elapsed = (nsec() - start) / (1000 * 1000);
|
elapsed = (nsec() - start) / (1000 * 1000);
|
||||||
if(verbose)
|
if(verbose)
|
||||||
fprint(2, "read(fds[0], buf, 1) returned %lld, elapsed = %d ms\n", res, elapsed);
|
fprint(2, "read(fds[0], buf, 1) returned %lld, elapsed = %d ms\n", res, elapsed);
|
||||||
if(!awakened(wkup) || res != -1 || elapsed < 900 || elapsed > 1300){
|
if(!awakened(wkup) || res != -1 || elapsed < 900 || elapsed > 1800){
|
||||||
print("FAIL: read\n");
|
print("FAIL: read\n");
|
||||||
exits("FAIL");
|
exits("FAIL");
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ main(void)
|
||||||
elapsed = (nsec() - start) / (1000 * 1000);
|
elapsed = (nsec() - start) / (1000 * 1000);
|
||||||
if(verbose)
|
if(verbose)
|
||||||
fprint(2, "writeTillBlock(fds[0]) returned %lld, elapsed = %d ms\n", res, elapsed);
|
fprint(2, "writeTillBlock(fds[0]) returned %lld, elapsed = %d ms\n", res, elapsed);
|
||||||
if(!awakened(wkup) || res >= 256 || elapsed < 900 || elapsed > 1300){
|
if(!awakened(wkup) || res >= 256 || elapsed < 900 || elapsed > 1800){
|
||||||
print("FAIL: write\n");
|
print("FAIL: write\n");
|
||||||
exits("FAIL");
|
exits("FAIL");
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,7 +208,7 @@ main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
average = average / NPROC / (1000 * 1000);
|
average = average / NPROC / (1000 * 1000);
|
||||||
|
|
||||||
if(average < 300) /* we asked for 1ms... we are dumb, after all */
|
if(average < 1000) /* we asked for 1ms... we are dumb, after all */
|
||||||
{
|
{
|
||||||
print("PASS\n");
|
print("PASS\n");
|
||||||
exits("PASS");
|
exits("PASS");
|
||||||
|
|
|
@ -112,7 +112,7 @@ waiter(int index)
|
||||||
if(verbose)
|
if(verbose)
|
||||||
print("reader %d: got the rlock in %lld ms\n", getpid(), (end - start) / (1000*1000));
|
print("reader %d: got the rlock in %lld ms\n", getpid(), (end - start) / (1000*1000));
|
||||||
runlock(&afterAWhile);
|
runlock(&afterAWhile);
|
||||||
if((end - start) / (1000*1000) > 1500)
|
if((end - start) / (1000*1000) > 2000)
|
||||||
postnote(PNGROUP, getpid(), smprint("fail: reader %d got the rlock after %lld ms", getpid(), (end - start) / (1000*1000)));
|
postnote(PNGROUP, getpid(), smprint("fail: reader %d got the rlock after %lld ms", getpid(), (end - start) / (1000*1000)));
|
||||||
} else {
|
} else {
|
||||||
if(verbose)
|
if(verbose)
|
||||||
|
@ -127,7 +127,7 @@ waiter(int index)
|
||||||
rwakeup(&rCompleted);
|
rwakeup(&rCompleted);
|
||||||
qunlock(&rl);
|
qunlock(&rl);
|
||||||
|
|
||||||
return (end - start) / (1000*1000) < 1300 ? nil : "FAIL";
|
return (end - start) / (1000*1000) < 2000 ? nil : "FAIL";
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -214,7 +214,7 @@ main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
average = average / NPROC / (1000 * 1000);
|
average = average / NPROC / (1000 * 1000);
|
||||||
|
|
||||||
if(average < 300) /* we asked for 1ms... we are dumb, after all */
|
if(average < 800) /* we asked for 1ms... we are dumb, after all */
|
||||||
{
|
{
|
||||||
print("PASS\n");
|
print("PASS\n");
|
||||||
exits("PASS");
|
exits("PASS");
|
||||||
|
|
|
@ -215,7 +215,7 @@ main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
average = average / NPROC / (1000 * 1000);
|
average = average / NPROC / (1000 * 1000);
|
||||||
|
|
||||||
if(average < 500) /* we asked for 1ms... we are dumb, after all */
|
if(average < 1000) /* we asked for 1ms... we are dumb, after all */
|
||||||
{
|
{
|
||||||
print("PASS\n");
|
print("PASS\n");
|
||||||
exits("PASS");
|
exits("PASS");
|
||||||
|
|
|
@ -210,7 +210,7 @@ main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
average = average / NPROC / (1000 * 1000);
|
average = average / NPROC / (1000 * 1000);
|
||||||
|
|
||||||
if(average < 300) /* we asked for 1ms... we are dumb, after all */
|
if(average < 1000) /* we asked for 1ms... we are dumb, after all */
|
||||||
{
|
{
|
||||||
print("PASS\n");
|
print("PASS\n");
|
||||||
exits("PASS");
|
exits("PASS");
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
fprintf(stdout, "hello, stdout\n");
|
||||||
|
fprintf(stderr, "hello, stderr\n");
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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,16 +11,21 @@ main(int argc, char **argv)
|
||||||
int p[2], ppgrp, opgrp, npgrp;
|
int p[2], ppgrp, opgrp, npgrp;
|
||||||
char c = '?';
|
char c = '?';
|
||||||
|
|
||||||
if (pipe(p) != 0)
|
if (pipe(p) != 0){
|
||||||
perror("pipe() error");
|
perror("pipe() error");
|
||||||
else {
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
ppgrp = getpgrp();
|
ppgrp = getpgrp();
|
||||||
printf("parent's pid %d; process group id %d\n", getpid(), ppgrp);
|
printf("parent's pid %d; process group id %d\n", getpid(), ppgrp);
|
||||||
if ((pid = fork()) == 0) {
|
if ((pid = fork()) == 0) {
|
||||||
opgrp = getpgrp();
|
opgrp = getpgrp();
|
||||||
printf("child's pid %d; process group id %d\n", getpid(), opgrp);
|
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);
|
write(p[1], &c, 1);
|
||||||
setsid();
|
|
||||||
npgrp = getpgrp();
|
npgrp = getpgrp();
|
||||||
if(opgrp == npgrp){
|
if(opgrp == npgrp){
|
||||||
printf("FAIL: setsid did not changed child's process group id\n");
|
printf("FAIL: setsid did not changed child's process group id\n");
|
||||||
|
@ -32,6 +37,8 @@ main(int argc, char **argv)
|
||||||
} else {
|
} else {
|
||||||
read(p[0], &c, 1);
|
read(p[0], &c, 1);
|
||||||
sleep(3);
|
sleep(3);
|
||||||
|
if(c == 'e')
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
if(ppgrp != getpgrp()){
|
if(ppgrp != getpgrp()){
|
||||||
printf("FAIL: parent's process group id changed from %d to %d\n", ppgrp, getpgrp());
|
printf("FAIL: parent's process group id changed from %d to %d\n", ppgrp, getpgrp());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
@ -39,15 +46,11 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
#ifndef WITH_SIGCHLD
|
#ifndef WITH_SIGCHLD
|
||||||
npgrp = getsid(pid);
|
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){
|
if(npgrp == ppgrp){
|
||||||
printf("FAIL: parent's getsid(%d) returned old process group id that should be changed\n", pid);
|
printf("FAIL: parent's getsid(%d) returned old process group id that should be changed\n", pid);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ test_output = /tmp/output-`{basename $test}
|
||||||
|
|
||||||
if ( test -e $test_output) rm $test_output
|
if ( test -e $test_output) rm $test_output
|
||||||
|
|
||||||
$test $test_output > /dev/null
|
$test > $test_output
|
||||||
if ( cat $test_output | grep 'FAIL' > /dev/null ) {
|
if ( cat $test_output | grep 'FAIL' > /dev/null ) {
|
||||||
cat $test_output
|
cat $test_output
|
||||||
echo FAIL
|
echo FAIL
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
signal(SIGQUIT, sigquit);
|
||||||
|
|
||||||
printf("\nChild going to loop...\n\n");
|
printf("\nChild going to loop...\n\n");
|
||||||
|
write(p[1], "", 1);
|
||||||
close(p[1]);
|
close(p[1]);
|
||||||
close(p[0]);
|
close(p[0]);
|
||||||
for(;;); /* loop for ever */
|
for(;;); /* loop for ever */
|
||||||
|
@ -65,11 +66,11 @@ main() {
|
||||||
else /* parent */
|
else /* parent */
|
||||||
{
|
{
|
||||||
signal(SIGCHLD,sigchld);
|
signal(SIGCHLD,sigchld);
|
||||||
close(p[1]);
|
if(read(p[0], &dummy, 1) != 1){
|
||||||
if(read(p[0], &dummy, 1) > 0){
|
printf("sync read");
|
||||||
printf("sync read received data");
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
close(p[1]);
|
||||||
close(p[0]);
|
close(p[0]);
|
||||||
printf("\nPARENT: sending SIGHUP\n\n");
|
printf("\nPARENT: sending SIGHUP\n\n");
|
||||||
kill(pid,SIGHUP);
|
kill(pid,SIGHUP);
|
||||||
|
|
|
@ -26,6 +26,7 @@ main() {
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
printf("\nI am the new child!\n\n");
|
printf("\nI am the new child!\n\n");
|
||||||
|
write(p[1], "", 1);
|
||||||
close(p[1]);
|
close(p[1]);
|
||||||
close(p[0]);
|
close(p[0]);
|
||||||
for(;;){
|
for(;;){
|
||||||
|
@ -36,11 +37,11 @@ main() {
|
||||||
}
|
}
|
||||||
else /* parent */
|
else /* parent */
|
||||||
{
|
{
|
||||||
close(p[1]);
|
if(read(p[0], &dummy, 1) != 1){
|
||||||
if(read(p[0], &dummy, 1) > 0){
|
printf("sync read");
|
||||||
printf("sync read received data");
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
close(p[1]);
|
||||||
close(p[0]);
|
close(p[0]);
|
||||||
printf("\nPARENT: sending SIGINT\n\n");
|
printf("\nPARENT: sending SIGINT\n\n");
|
||||||
kill(pid,SIGINT);
|
kill(pid,SIGINT);
|
||||||
|
|
|
@ -28,6 +28,7 @@ main() {
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
signal(SIGCONT,sigcont); /* set function calls */
|
signal(SIGCONT,sigcont); /* set function calls */
|
||||||
printf("Child going to loop...\n");
|
printf("Child going to loop...\n");
|
||||||
|
write(p[1], "", 1);
|
||||||
close(p[1]);
|
close(p[1]);
|
||||||
close(p[0]);
|
close(p[0]);
|
||||||
for(;;){
|
for(;;){
|
||||||
|
@ -38,11 +39,8 @@ main() {
|
||||||
}
|
}
|
||||||
else /* parent */
|
else /* parent */
|
||||||
{
|
{
|
||||||
|
read(p[0], &dummy, 1);
|
||||||
close(p[1]);
|
close(p[1]);
|
||||||
if(read(p[0], &dummy, 1) > 0){
|
|
||||||
printf("sync read received data");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
close(p[0]);
|
close(p[0]);
|
||||||
printf("PARENT: sending SIGCONT\n\n");
|
printf("PARENT: sending SIGCONT\n\n");
|
||||||
kill(pid,SIGCONT);
|
kill(pid,SIGCONT);
|
||||||
|
|
|
@ -22,7 +22,8 @@ void childloop(void)
|
||||||
{
|
{
|
||||||
signal(SIGCONT,sigcont); /* set function calls */
|
signal(SIGCONT,sigcont); /* set function calls */
|
||||||
signal(SIGSTOP,sigstop); /* set function calls */
|
signal(SIGSTOP,sigstop); /* set function calls */
|
||||||
printf("Child going to loop...\n");
|
printf("Child %d going to loop...\n", getpid());
|
||||||
|
write(p[1], "", 1);
|
||||||
close(p[1]);
|
close(p[1]);
|
||||||
close(p[0]);
|
close(p[0]);
|
||||||
for(;;){
|
for(;;){
|
||||||
|
@ -54,11 +55,8 @@ main() {
|
||||||
}
|
}
|
||||||
else /* parent */
|
else /* parent */
|
||||||
{
|
{
|
||||||
|
read(p[0], &dummy, 1);
|
||||||
close(p[1]);
|
close(p[1]);
|
||||||
if(read(p[0], &dummy, 1) > 0){
|
|
||||||
printf("sync read received data");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
close(p[0]);
|
close(p[0]);
|
||||||
sleep(2);
|
sleep(2);
|
||||||
printf("PARENT: sending SIGSTOP\n");
|
printf("PARENT: sending SIGSTOP\n");
|
||||||
|
|
|
@ -47,6 +47,7 @@ main() {
|
||||||
signal(SIGQUIT, sigquit);
|
signal(SIGQUIT, sigquit);
|
||||||
|
|
||||||
printf("Child going to loop...\n");
|
printf("Child going to loop...\n");
|
||||||
|
write(p[1], "", 1);
|
||||||
close(p[1]);
|
close(p[1]);
|
||||||
close(p[0]);
|
close(p[0]);
|
||||||
for(;;); /* loop for ever */
|
for(;;); /* loop for ever */
|
||||||
|
@ -54,11 +55,8 @@ main() {
|
||||||
else /* parent */
|
else /* parent */
|
||||||
{
|
{
|
||||||
signal(SIGCHLD,sigchld);
|
signal(SIGCHLD,sigchld);
|
||||||
|
read(p[0], &dummy, 1);
|
||||||
close(p[1]);
|
close(p[1]);
|
||||||
if(read(p[0], &dummy, 1) > 0){
|
|
||||||
printf("sync read received data");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
close(p[0]);
|
close(p[0]);
|
||||||
printf("PARENT: sending SIGHUP\n");
|
printf("PARENT: sending SIGHUP\n");
|
||||||
kill(pid,SIGHUP);
|
kill(pid,SIGHUP);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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": [
|
"SourceFilesCmd": [
|
||||||
"000-hello.c",
|
"000-hello.c",
|
||||||
|
"001-hello.c",
|
||||||
|
"002-atexit.c",
|
||||||
"010-fork.c",
|
"010-fork.c",
|
||||||
"020-waitpid.c",
|
"020-waitpid.c",
|
||||||
"030-pause.c",
|
"030-pause.c",
|
||||||
"031-setjmp.c",
|
"031-setjmp.c",
|
||||||
"040-gettimeofday.c",
|
"040-gettimeofday.c",
|
||||||
|
"041-env.c",
|
||||||
"050-setsid.c",
|
"050-setsid.c",
|
||||||
"100-files.c",
|
"100-files.c",
|
||||||
"101-files.c",
|
"101-files.c",
|
||||||
"102-files.c",
|
"102-files.c",
|
||||||
"103-files.c",
|
"103-files.c",
|
||||||
|
"120-fcntl.c",
|
||||||
|
"121-fcntl.c",
|
||||||
"200-signals.c",
|
"200-signals.c",
|
||||||
"201-signals.c",
|
"201-signals.c",
|
||||||
"202-signals.c",
|
"202-signals.c",
|
||||||
"203-signals.c",
|
"203-signals.c",
|
||||||
"204-signals.c",
|
"204-signals.c",
|
||||||
"205-signals.c"
|
"205-signals.c",
|
||||||
|
"206-signals.c",
|
||||||
|
"207-sigsuspend.c",
|
||||||
|
"208-sigpending.c",
|
||||||
|
"209-sigwaitinfo.c",
|
||||||
|
"210-sigtimedwait.c",
|
||||||
|
"211-sigtimedwait.c",
|
||||||
|
"212-sigwait.c",
|
||||||
|
"213-sigqueue.c",
|
||||||
|
"214-sigsetjmp.c",
|
||||||
|
"215-sigprocmask.c"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"SIGCHLDTests": {
|
"SIGCHLDTests": {
|
||||||
|
@ -84,20 +99,37 @@
|
||||||
],
|
],
|
||||||
"SourceFilesCmd": [
|
"SourceFilesCmd": [
|
||||||
"000-hello.c",
|
"000-hello.c",
|
||||||
|
"001-hello.c",
|
||||||
|
"002-atexit.c",
|
||||||
"010-fork.c",
|
"010-fork.c",
|
||||||
"020-waitpid.c",
|
"020-waitpid.c",
|
||||||
"030-pause.c",
|
"030-pause.c",
|
||||||
|
"031-setjmp.c",
|
||||||
"040-gettimeofday.c",
|
"040-gettimeofday.c",
|
||||||
|
"041-env.c",
|
||||||
|
"050-setsid.c",
|
||||||
"100-files.c",
|
"100-files.c",
|
||||||
"101-files.c",
|
"101-files.c",
|
||||||
"102-files.c",
|
"102-files.c",
|
||||||
"103-files.c",
|
"103-files.c",
|
||||||
|
"120-fcntl.c",
|
||||||
|
"121-fcntl.c",
|
||||||
"200-signals.c",
|
"200-signals.c",
|
||||||
"201-signals.c",
|
"201-signals.c",
|
||||||
"202-signals.c",
|
"202-signals.c",
|
||||||
"203-signals.c",
|
"203-signals.c",
|
||||||
"204-signals.c",
|
"204-signals.c",
|
||||||
"205-signals.c"
|
"205-signals.c",
|
||||||
|
"206-signals.c",
|
||||||
|
"207-sigsuspend.c",
|
||||||
|
"208-sigpending.c",
|
||||||
|
"209-sigwaitinfo.c",
|
||||||
|
"210-sigtimedwait.c",
|
||||||
|
"211-sigtimedwait.c",
|
||||||
|
"212-sigwait.c",
|
||||||
|
"213-sigqueue.c",
|
||||||
|
"214-sigsetjmp.c",
|
||||||
|
"215-sigprocmask.c"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"NewlibTestsuite": {
|
"NewlibTestsuite": {
|
||||||
|
|
|
@ -27,18 +27,34 @@ qa_exit_translator(int status)
|
||||||
* should return PASS/FAIL
|
* should return PASS/FAIL
|
||||||
*/
|
*/
|
||||||
if(status == 0){
|
if(status == 0){
|
||||||
jehanne_print("PASS\n");
|
|
||||||
return "PASS";
|
return "PASS";
|
||||||
} else {
|
} else {
|
||||||
jehanne_print("FAIL: " __POSIX_EXIT_PREFIX "%d\n", status);
|
|
||||||
return "FAIL";
|
return "FAIL";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
qa_exit_printer(int status, void *_)
|
||||||
|
{
|
||||||
|
extern int printf(const char *format, ...);
|
||||||
|
if(jehanne_getpid() == jehanne_getmainpid()){
|
||||||
|
/* the QA test may fork, but only the main process
|
||||||
|
* should return PASS/FAIL
|
||||||
|
*/
|
||||||
|
if(status == 0){
|
||||||
|
printf("PASS\n");
|
||||||
|
} else {
|
||||||
|
printf("FAIL: " __POSIX_EXIT_PREFIX "%d\n", status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
__application_newlib_init(void)
|
__application_newlib_init(void)
|
||||||
{
|
{
|
||||||
|
extern int on_exit(void (*func)(int, void*), void* arg);
|
||||||
|
on_exit(qa_exit_printer, nil);
|
||||||
libposix_translate_exit_status(qa_exit_translator);
|
libposix_translate_exit_status(qa_exit_translator);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,19 +27,35 @@ qa_exit_translator(int status)
|
||||||
* should return PASS/FAIL
|
* should return PASS/FAIL
|
||||||
*/
|
*/
|
||||||
if(status == 0){
|
if(status == 0){
|
||||||
jehanne_print("PASS\n");
|
|
||||||
return "PASS";
|
return "PASS";
|
||||||
} else {
|
} else {
|
||||||
jehanne_print("FAIL: " __POSIX_EXIT_PREFIX "%d\n", status);
|
|
||||||
return "FAIL";
|
return "FAIL";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
qa_exit_printer(int status, void *_)
|
||||||
|
{
|
||||||
|
extern int printf(const char *format, ...);
|
||||||
|
if(jehanne_getpid() == jehanne_getmainpid()){
|
||||||
|
/* the QA test may fork, but only the main process
|
||||||
|
* should return PASS/FAIL
|
||||||
|
*/
|
||||||
|
if(status == 0){
|
||||||
|
printf("PASS\n");
|
||||||
|
} else {
|
||||||
|
printf("FAIL: " __POSIX_EXIT_PREFIX "%d\n", status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
__application_newlib_init(void)
|
__application_newlib_init(void)
|
||||||
{
|
{
|
||||||
|
extern int on_exit(void (*func)(int, void*), void* arg);
|
||||||
|
on_exit(qa_exit_printer, nil);
|
||||||
libposix_translate_exit_status(qa_exit_translator);
|
libposix_translate_exit_status(qa_exit_translator);
|
||||||
libposix_emulate_SIGCHLD();
|
libposix_emulate_SIGCHLD();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,18 @@
|
||||||
* #include <u.h>
|
* #include <u.h>
|
||||||
* #include <posix.h>
|
* #include <posix.h>
|
||||||
*
|
*
|
||||||
* Defining _LIBPOSIX_H before the include allow you to just get dirent
|
* Defining _LIBPOSIX_H before the include allow you to just get
|
||||||
* definition.
|
* data structure definition.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LIBPOSIX_DIRENT
|
#ifndef _LIBPOSIX_DEF
|
||||||
#define _LIBPOSIX_DIRENT
|
#define _LIBPOSIX_DEF
|
||||||
|
|
||||||
|
struct timespec
|
||||||
|
{
|
||||||
|
long tv_sec;
|
||||||
|
long tv_nsec;
|
||||||
|
};
|
||||||
|
|
||||||
/* dirent alias of stat(5) message.
|
/* dirent alias of stat(5) message.
|
||||||
* We (ab)use the fact that both 9P and Jehanne are little endian.
|
* We (ab)use the fact that both 9P and Jehanne are little endian.
|
||||||
|
@ -75,13 +81,7 @@ struct __attribute__((__packed__)) dirent
|
||||||
#define DT_SOCK 12
|
#define DT_SOCK 12
|
||||||
#define DT_WHT 14
|
#define DT_WHT 14
|
||||||
|
|
||||||
#endif /* _LIBPOSIX_DIRENT */
|
/* getrusage who */
|
||||||
|
|
||||||
#ifndef _LIBPOSIX_H
|
|
||||||
#define _LIBPOSIX_H
|
|
||||||
|
|
||||||
typedef unsigned long clock_t;
|
|
||||||
|
|
||||||
typedef enum PosixRUsages
|
typedef enum PosixRUsages
|
||||||
{
|
{
|
||||||
PosixRUsageSelf = 0,
|
PosixRUsageSelf = 0,
|
||||||
|
@ -90,10 +90,170 @@ typedef enum PosixRUsages
|
||||||
PosixRUsageUnknown = -1
|
PosixRUsageUnknown = -1
|
||||||
} PosixRUsages;
|
} PosixRUsages;
|
||||||
|
|
||||||
|
/* errno values */
|
||||||
|
#define _ERRNO_H // skip the Posix part, we just need the enum
|
||||||
|
#include <apw/errno.h>
|
||||||
|
|
||||||
|
/* signals */
|
||||||
|
typedef unsigned long PosixSignalMask;
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum PosixSigProcMaskAction
|
||||||
|
{
|
||||||
|
PosixSPMSetMask = 0,
|
||||||
|
PosixSPMBlock = 1,
|
||||||
|
PosixSPMUnblock = 2
|
||||||
|
} PosixSigProcMaskAction;
|
||||||
|
|
||||||
|
#define PosixNumberOfSignals (sizeof(PosixSignalMask)*7)
|
||||||
|
typedef enum PosixSignals
|
||||||
|
{
|
||||||
|
PosixSIGABRT = 1,
|
||||||
|
PosixSIGALRM,
|
||||||
|
PosixSIGBUS,
|
||||||
|
PosixSIGCHLD,
|
||||||
|
PosixSIGCONT,
|
||||||
|
PosixSIGFPE,
|
||||||
|
PosixSIGHUP,
|
||||||
|
PosixSIGILL,
|
||||||
|
PosixSIGINT,
|
||||||
|
PosixSIGKILL,
|
||||||
|
PosixSIGPIPE,
|
||||||
|
PosixSIGQUIT,
|
||||||
|
PosixSIGSEGV,
|
||||||
|
PosixSIGSTOP,
|
||||||
|
PosixSIGTERM,
|
||||||
|
PosixSIGTSTP,
|
||||||
|
PosixSIGTTIN,
|
||||||
|
PosixSIGTTOU,
|
||||||
|
PosixSIGUSR1,
|
||||||
|
PosixSIGUSR2,
|
||||||
|
PosixSIGPOLL,
|
||||||
|
PosixSIGPROF,
|
||||||
|
PosixSIGSYS,
|
||||||
|
PosixSIGTRAP,
|
||||||
|
PosixSIGURG,
|
||||||
|
PosixSIGVTALRM,
|
||||||
|
PosixSIGXCPU,
|
||||||
|
PosixSIGXFSZ,
|
||||||
|
|
||||||
|
/* Optional Signals */
|
||||||
|
PosixSIGIOT,
|
||||||
|
PosixSIGEMT,
|
||||||
|
PosixSIGSTKFLT,
|
||||||
|
PosixSIGIO,
|
||||||
|
PosixSIGPWR,
|
||||||
|
PosixSIGINFO,
|
||||||
|
PosixSIGLOST,
|
||||||
|
PosixSIGWINCH,
|
||||||
|
PosixSIGUNUSED,
|
||||||
|
|
||||||
|
PosixSIGRTMIN,
|
||||||
|
PosixSIGRTMAX = PosixNumberOfSignals
|
||||||
|
} PosixSignals;
|
||||||
|
|
||||||
|
typedef enum PosixSigActionFlags
|
||||||
|
{
|
||||||
|
/* supported flags */
|
||||||
|
PosixSAFSigInfo = 1<<0,
|
||||||
|
PosixSAFRestart = 1<<1,
|
||||||
|
PosixSAFNoChildrenStop = 1<<2,
|
||||||
|
PosixSAFResetHandler = 1<<3,
|
||||||
|
PosixSAFNoChildrenWait = 1<<4,
|
||||||
|
|
||||||
|
/* ignored flags */
|
||||||
|
PosixSAFNoDefer = 1<<16, /* notes are not reentrant */
|
||||||
|
PosixSAFOnStack = 1<<17,
|
||||||
|
PosixSAFDisable = 1<<18
|
||||||
|
} PosixSigActionFlags;
|
||||||
|
|
||||||
|
typedef enum PosixSigInfoCodes
|
||||||
|
{
|
||||||
|
PosixSIUser = 1,
|
||||||
|
PosixSIQueue,
|
||||||
|
PosixSITimer,
|
||||||
|
PosixSIAsyncIO,
|
||||||
|
PosixSIMsgQueued,
|
||||||
|
|
||||||
|
PosixSIFaultMapError,
|
||||||
|
PosixSIFaultAccessError,
|
||||||
|
|
||||||
|
PosixSIChildExited,
|
||||||
|
PosixSIChildKilled,
|
||||||
|
PosixSIChildDumped,
|
||||||
|
PosixSIChildTrapped,
|
||||||
|
PosixSIChildStopped,
|
||||||
|
PosixSIChildContinued
|
||||||
|
} PosixSigInfoCodes;
|
||||||
|
|
||||||
|
union sigval {
|
||||||
|
int sival_int; /* Integer signal value */
|
||||||
|
void* sival_ptr; /* Pointer signal value */
|
||||||
|
void* _si_addr; /* Address of faulting address */
|
||||||
|
int _si_status; /* Child exit status */
|
||||||
|
uintptr_t _sival_raw; /* Raw value */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sigevent {
|
||||||
|
int sigev_notify; /* Notification type */
|
||||||
|
int sigev_signo; /* Signal number */
|
||||||
|
union sigval sigev_value; /* Signal value */
|
||||||
|
void (*sigev_notify_function)( union sigval );
|
||||||
|
/* Notification function */
|
||||||
|
long *sigev_notify_attributes; /* Notification Attributes */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int si_signo; /* Signal number */
|
||||||
|
int si_code; /* Cause of the signal */
|
||||||
|
int si_errno;
|
||||||
|
int si_pid; /* Pid of sender */
|
||||||
|
int si_uid; /* Uid of sender */
|
||||||
|
union sigval si_value; /* Signal value */
|
||||||
|
} PosixSignalInfo;
|
||||||
|
|
||||||
|
#define si_addr si_value._si_addr
|
||||||
|
#define si_status si_value._si_status
|
||||||
|
|
||||||
|
typedef void (*PosixSigHandler)(int);
|
||||||
|
typedef void (*PosixSigAction)(int, PosixSignalInfo *, void * );
|
||||||
|
|
||||||
|
struct sigaction {
|
||||||
|
int sa_flags; /* Special flags to affect behavior of signal */
|
||||||
|
PosixSignalMask sa_mask; /* Additional set of signals to be blocked */
|
||||||
|
/* during execution of signal-catching */
|
||||||
|
/* function. */
|
||||||
|
union {
|
||||||
|
PosixSigHandler _handler; /* SIG_DFL, SIG_IGN, or pointer to a function */
|
||||||
|
PosixSigAction _sigaction;
|
||||||
|
} _signal_handlers;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define sa_handler _signal_handlers._handler
|
||||||
|
#define sa_sigaction _signal_handlers._sigaction
|
||||||
|
|
||||||
|
typedef enum PosixFDCmds
|
||||||
|
{
|
||||||
|
PosixFDCDupFD = 1,
|
||||||
|
PosixFDCDupFDCloseOnExec,
|
||||||
|
PosixFDCGetFD,
|
||||||
|
PosixFDCSetFD,
|
||||||
|
PosixFDCGetFL,
|
||||||
|
PosixFDCSetFL
|
||||||
|
} PosixFDCmds;
|
||||||
|
|
||||||
|
#endif /* _LIBPOSIX_DEF */
|
||||||
|
|
||||||
|
#ifndef _LIBPOSIX_H
|
||||||
|
#define _LIBPOSIX_H
|
||||||
|
|
||||||
|
typedef unsigned long clock_t;
|
||||||
|
|
||||||
#define __POSIX_EXIT_PREFIX "posix error "
|
#define __POSIX_EXIT_PREFIX "posix error "
|
||||||
#define __POSIX_EXIT_SIGNAL_PREFIX "terminated by posix signal "
|
#define __POSIX_EXIT_SIGNAL_PREFIX "terminated by posix signal "
|
||||||
#define __POSIX_SIGNAL_PREFIX "posix: "
|
#define __POSIX_SIGNAL_PREFIX "posix: "
|
||||||
|
|
||||||
|
extern unsigned int POSIX_alarm(int *errnop, unsigned int seconds);
|
||||||
extern int POSIX_access(int *errnop, const char *path, int amode);
|
extern int POSIX_access(int *errnop, const char *path, int amode);
|
||||||
extern int POSIX_dup(int *errnop, int fildes);
|
extern int POSIX_dup(int *errnop, int fildes);
|
||||||
extern int POSIX_dup2(int *errnop, int fildes, int fildes2);
|
extern int POSIX_dup2(int *errnop, int fildes, int fildes2);
|
||||||
|
@ -134,6 +294,8 @@ extern int POSIX_waitpid(int *errnop, int pid, int *status, int options);
|
||||||
extern long POSIX_write(int *errnop, int fd, const void *buf, size_t len);
|
extern long POSIX_write(int *errnop, int fd, const void *buf, size_t len);
|
||||||
extern int POSIX_gettimeofday(int *errnop, void *timeval, void *timezone);
|
extern int POSIX_gettimeofday(int *errnop, void *timeval, void *timezone);
|
||||||
extern char* POSIX_getenv(int *errnop, const char *name);
|
extern char* POSIX_getenv(int *errnop, const char *name);
|
||||||
|
extern int POSIX_setenv(int *errno, const char *name, const char *value, int overwrite);
|
||||||
|
extern int POSIX_unsetenv(int *errnop, const char *name);
|
||||||
extern void *POSIX_sbrk(int *errnop, ptrdiff_t incr);
|
extern void *POSIX_sbrk(int *errnop, ptrdiff_t incr);
|
||||||
extern void * POSIX_malloc(int *errnop, size_t size);
|
extern void * POSIX_malloc(int *errnop, size_t size);
|
||||||
extern void *POSIX_realloc(int *errnop, void *ptr, size_t size);
|
extern void *POSIX_realloc(int *errnop, void *ptr, size_t size);
|
||||||
|
@ -142,6 +304,19 @@ extern void POSIX_free(void *ptr);
|
||||||
extern unsigned int POSIX_sleep(unsigned int seconds);
|
extern unsigned int POSIX_sleep(unsigned int seconds);
|
||||||
extern int POSIX_pipe(int *errnop, int fildes[2]);
|
extern int POSIX_pipe(int *errnop, int fildes[2]);
|
||||||
extern int POSIX_umask(int *errnop, int mask);
|
extern int POSIX_umask(int *errnop, int mask);
|
||||||
|
extern int POSIX_fcntl(int *errnop, int fd, PosixFDCmds cmd, uintptr_t arg);
|
||||||
|
|
||||||
|
extern int POSIX_sigaddset(int *errnop, PosixSignalMask *set, int signo);
|
||||||
|
extern int POSIX_sigdelset(int *errnop, PosixSignalMask *set, int signo);
|
||||||
|
extern int POSIX_sigismember(int *errnop, const PosixSignalMask *set, int signo);
|
||||||
|
extern int POSIX_sigfillset(int *errnop, PosixSignalMask *set);
|
||||||
|
extern int POSIX_sigemptyset(int *errnop, PosixSignalMask *set);
|
||||||
|
extern int POSIX_sigprocmask(int *errnop, PosixSigProcMaskAction how, const PosixSignalMask *set, PosixSignalMask *oset);
|
||||||
|
extern int POSIX_sigpending(int *errnop, PosixSignalMask *set);
|
||||||
|
extern int POSIX_sigsuspend(int *errnop, const PosixSignalMask *mask);
|
||||||
|
extern int POSIX_sigaction(int *errnop, int signo, const struct sigaction *act, struct sigaction *old);
|
||||||
|
extern int POSIX_sigtimedwait(int *errnop, const PosixSignalMask *set, PosixSignalInfo *info, const struct timespec *timeout);
|
||||||
|
extern int POSIX_sigqueue(int *errnop, int pid, int signo, const union sigval value);
|
||||||
|
|
||||||
extern int POSIX_getuid(int *errnop);
|
extern int POSIX_getuid(int *errnop);
|
||||||
extern int POSIX_geteuid(int *errnop);
|
extern int POSIX_geteuid(int *errnop);
|
||||||
|
@ -159,72 +334,26 @@ extern int POSIX_setpgid(int *errnop, int pid, int pgid);
|
||||||
extern int POSIX_getsid(int *errnop, int pid);
|
extern int POSIX_getsid(int *errnop, int pid);
|
||||||
extern int POSIX_setsid(int *errnop);
|
extern int POSIX_setsid(int *errnop);
|
||||||
|
|
||||||
|
extern int POSIX_tcgetpgrp(int *errnop, int fd);
|
||||||
|
extern int POSIX_tcsetpgrp(int *errnop, int fd, int pgrp);
|
||||||
|
|
||||||
extern int libposix_getdents(int *errnop, int fd, char *buf, int buf_bytes);
|
extern int libposix_getdents(int *errnop, int fd, char *buf, int buf_bytes);
|
||||||
|
extern PosixError libposix_translate_kernel_errors(const char *msg);
|
||||||
|
|
||||||
/* Library initialization
|
/* Library initialization
|
||||||
*/
|
*/
|
||||||
#define _ERRNO_H // skip the Posix part, we just need the enum
|
|
||||||
#include <apw/errno.h>
|
|
||||||
|
|
||||||
typedef enum PosixSignals
|
|
||||||
{
|
|
||||||
PosixSIGABRT = 1,
|
|
||||||
PosixSIGALRM,
|
|
||||||
PosixSIGBUS,
|
|
||||||
PosixSIGCHLD,
|
|
||||||
PosixSIGCONT,
|
|
||||||
PosixSIGFPE,
|
|
||||||
PosixSIGHUP,
|
|
||||||
PosixSIGILL,
|
|
||||||
PosixSIGINT,
|
|
||||||
PosixSIGKILL,
|
|
||||||
PosixSIGPIPE,
|
|
||||||
PosixSIGQUIT,
|
|
||||||
PosixSIGSEGV,
|
|
||||||
PosixSIGSTOP,
|
|
||||||
PosixSIGTERM,
|
|
||||||
PosixSIGTSTP,
|
|
||||||
PosixSIGTTIN,
|
|
||||||
PosixSIGTTOU,
|
|
||||||
PosixSIGUSR1,
|
|
||||||
PosixSIGUSR2,
|
|
||||||
PosixSIGPOLL,
|
|
||||||
PosixSIGPROF,
|
|
||||||
PosixSIGSYS,
|
|
||||||
PosixSIGTRAP,
|
|
||||||
PosixSIGURG,
|
|
||||||
PosixSIGVTALRM,
|
|
||||||
PosixSIGXCPU,
|
|
||||||
PosixSIGXFSZ,
|
|
||||||
|
|
||||||
/* Optional Signals */
|
|
||||||
PosixSIGIOT,
|
|
||||||
PosixSIGEMT,
|
|
||||||
PosixSIGSTKFLT,
|
|
||||||
PosixSIGIO,
|
|
||||||
PosixSIGCLD,
|
|
||||||
PosixSIGPWR,
|
|
||||||
PosixSIGINFO,
|
|
||||||
PosixSIGLOST,
|
|
||||||
PosixSIGWINCH,
|
|
||||||
PosixSIGUNUSED,
|
|
||||||
|
|
||||||
PosixNumberOfSignals
|
|
||||||
} PosixSignals;
|
|
||||||
|
|
||||||
/* Initialize libposix. Should call
|
/* Initialize libposix. Should call
|
||||||
*
|
*
|
||||||
* libposix_define_errno to set the value of each PosixError
|
* libposix_define_errno to set the value of each PosixError
|
||||||
* libposix_define_signal to set the value of each PosixSignal
|
|
||||||
* libposix_define_at_fdcwd to set the value of AT_FDCWD (for fchmodat)
|
* libposix_define_at_fdcwd to set the value of AT_FDCWD (for fchmodat)
|
||||||
* libposix_translate_error to translate error strings to PosixError
|
* libposix_translate_error to translate error strings to PosixError
|
||||||
* libposix_set_signal_trampoline to dispatch signal received as notes
|
|
||||||
* libposix_set_stat_reader
|
* libposix_set_stat_reader
|
||||||
* libposix_set_tms_reader
|
* libposix_set_tms_reader
|
||||||
* libposix_set_timeval_reader
|
* libposix_set_timeval_reader
|
||||||
* libposix_set_timezone_reader
|
* libposix_set_timezone_reader
|
||||||
*/
|
*/
|
||||||
typedef void (*PosixInit)(void);
|
typedef void (*PosixInit)(int argc, char *argv[]);
|
||||||
extern void libposix_init(int argc, char *argv[], PosixInit init) __attribute__((noreturn));
|
extern void libposix_init(int argc, char *argv[], PosixInit init) __attribute__((noreturn));
|
||||||
|
|
||||||
/* Translate an error string to a PosixError, in the context of the
|
/* Translate an error string to a PosixError, in the context of the
|
||||||
|
@ -327,23 +456,11 @@ typedef char* (*PosixExitStatusTranslator)(int status);
|
||||||
|
|
||||||
extern int libposix_translate_exit_status(PosixExitStatusTranslator translator);
|
extern int libposix_translate_exit_status(PosixExitStatusTranslator translator);
|
||||||
|
|
||||||
/* Dispatch the signal to the registered handlers.
|
/* Execute process disposition (executed when main returns)
|
||||||
*/
|
*/
|
||||||
typedef enum PosixSignalAction
|
typedef void (*PosixProcessDisposer)(int status);
|
||||||
{
|
|
||||||
SignalCatched = 1,
|
|
||||||
SignalIgnored,
|
|
||||||
SignalError,
|
|
||||||
SignalDefault
|
|
||||||
} PosixSignalAction;
|
|
||||||
typedef PosixSignalAction (*PosixSignalTrampoline)(int signal);
|
|
||||||
|
|
||||||
extern int libposix_set_signal_trampoline(PosixSignalTrampoline trampoline);
|
|
||||||
|
|
||||||
extern int libposix_define_signal(PosixSignals signal, int code);
|
|
||||||
|
|
||||||
extern int libposix_define_realtime_signals(int sigrtmin, int sigrtmax);
|
|
||||||
|
|
||||||
|
extern int libposix_on_process_disposition(PosixProcessDisposer dispose);
|
||||||
|
|
||||||
/* Enable SIGCHLD emulation
|
/* Enable SIGCHLD emulation
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
{
|
{
|
||||||
"disk": {
|
"SystemTools": {
|
||||||
"Include": [
|
"Include": [
|
||||||
"../cmd.json"
|
"../cmd.json"
|
||||||
],
|
],
|
||||||
"Install": "/arch/$ARCH/cmd/sys/",
|
"Install": "/arch/$ARCH/cmd/sys/",
|
||||||
|
"Oflags": [
|
||||||
|
"-static",
|
||||||
|
"-lc"
|
||||||
|
],
|
||||||
"Projects": [
|
"Projects": [
|
||||||
"call/"
|
"call/"
|
||||||
],
|
],
|
||||||
|
|
|
@ -22,11 +22,11 @@
|
||||||
"/sys/src/lib/mp/",
|
"/sys/src/lib/mp/",
|
||||||
"/sys/src/lib/ndb/",
|
"/sys/src/lib/ndb/",
|
||||||
"/sys/src/lib/plumb/",
|
"/sys/src/lib/plumb/",
|
||||||
"/sys/src/lib/posix/",
|
|
||||||
"/sys/src/lib/regexp/",
|
"/sys/src/lib/regexp/",
|
||||||
"/sys/src/lib/sec/",
|
"/sys/src/lib/sec/",
|
||||||
"/sys/src/lib/stdio/",
|
"/sys/src/lib/stdio/",
|
||||||
"/sys/src/lib/thread/"
|
"/sys/src/lib/thread/",
|
||||||
|
"/sys/src/lib/posix/"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"LibPosix": {
|
"LibPosix": {
|
||||||
"Cflags": [
|
"Cflags": [
|
||||||
|
"-DARCH=\"$ARCH\"",
|
||||||
"-fasm",
|
"-fasm",
|
||||||
"-I."
|
"-I."
|
||||||
],
|
],
|
||||||
|
@ -12,16 +13,37 @@
|
||||||
"SourceFiles": [
|
"SourceFiles": [
|
||||||
"environment.c",
|
"environment.c",
|
||||||
"errors.c",
|
"errors.c",
|
||||||
|
"fcntl.c",
|
||||||
"files.c",
|
"files.c",
|
||||||
"ids.c",
|
"ids.c",
|
||||||
"initlib.c",
|
"initlib.c",
|
||||||
|
"kill.c",
|
||||||
"links.c",
|
"links.c",
|
||||||
"memory.c",
|
"memory.c",
|
||||||
"others.c",
|
"others.c",
|
||||||
"processes.c",
|
"processes.c",
|
||||||
"sigchlds.c",
|
"sigchlds.c",
|
||||||
"signals.c",
|
"signals.c",
|
||||||
|
"sigqueue.c",
|
||||||
|
"sigsets.c",
|
||||||
|
"sigsuspend.c",
|
||||||
|
"termios.c",
|
||||||
"timers.c"
|
"timers.c"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"SignalHelper": {
|
||||||
|
"Include": [
|
||||||
|
"../../cmd/cmd.json"
|
||||||
|
],
|
||||||
|
"Install": "/arch/$ARCH/cmd/sys/",
|
||||||
|
"Oflags": [
|
||||||
|
"-static",
|
||||||
|
"-lposix",
|
||||||
|
"-l9p2000",
|
||||||
|
"-lc"
|
||||||
|
],
|
||||||
|
"SourceFilesCmd": [
|
||||||
|
"posixly.c"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,12 +89,96 @@ put_in_list(EnvVar* newenv)
|
||||||
wunlock(&list_lock);
|
wunlock(&list_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
static int
|
||||||
POSIX_getenv(int *errno, const char *name)
|
write_env_file(const char *name, const char *value, int size)
|
||||||
|
{
|
||||||
|
int f;
|
||||||
|
char buf[MAX_ENVNAME_LEN];
|
||||||
|
|
||||||
|
snprint(buf, sizeof(buf), "/env/%s", name);
|
||||||
|
f = ocreate(buf, OWRITE, 664);
|
||||||
|
if(f < 0)
|
||||||
|
return 0;
|
||||||
|
if(write(f, value, size) < 0){
|
||||||
|
close(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
close(f);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
POSIX_setenv(int *errnop, const char *name, const char *value, int overwrite)
|
||||||
{
|
{
|
||||||
EnvVar* e;
|
EnvVar* e;
|
||||||
if(name == nil || name[0] == 0 || strchr(name, '=') == nil){
|
if(name == nil || name[0] == 0 || strchr(name, '=') != nil){
|
||||||
*errno = PosixEINVAL;
|
*errnop = PosixEINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(!overwrite && POSIX_getenv(errnop, name) != nil)
|
||||||
|
return 0;
|
||||||
|
if(strlen(name) > 127){
|
||||||
|
*errnop = PosixENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
e = malloc(sizeof(EnvVar));
|
||||||
|
e->next = nil;
|
||||||
|
e->value = strdup(value); // see free_env
|
||||||
|
e->name = strdup(name);
|
||||||
|
if(!write_env_file(name, e->value, strlen(value) + 1)){
|
||||||
|
free_env(e);
|
||||||
|
*errnop = PosixENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
put_in_list(e);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
POSIX_unsetenv(int *errnop, const char *name)
|
||||||
|
{
|
||||||
|
EnvVar* e, **o;
|
||||||
|
char buf[MAX_ENVNAME_LEN];
|
||||||
|
if(name == nil || name[0] == 0 || strchr(name, '=') != nil){
|
||||||
|
*errnop = PosixEINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(POSIX_getenv(errnop, name) == nil)
|
||||||
|
return 0;
|
||||||
|
e = malloc(sizeof(EnvVar));
|
||||||
|
|
||||||
|
wlock(&list_lock);
|
||||||
|
|
||||||
|
e = list_start;
|
||||||
|
o = &list_start;
|
||||||
|
while(e != nil){
|
||||||
|
if(strcmp(e->name, name) == 0){
|
||||||
|
*o = e->next;
|
||||||
|
free(e);
|
||||||
|
e = nil; // done
|
||||||
|
} else {
|
||||||
|
o = &e->next;
|
||||||
|
e = *o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wunlock(&list_lock);
|
||||||
|
|
||||||
|
snprint(buf, sizeof(buf), "/env/%s", name);
|
||||||
|
remove(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
POSIX_getenv(int *errnop, const char *name)
|
||||||
|
{
|
||||||
|
EnvVar* e;
|
||||||
|
if(name == nil || name[0] == 0 || strchr(name, '=') != nil){
|
||||||
|
*errnop = PosixEINVAL;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
if(strlen(name) > 127){
|
||||||
|
*errnop = PosixEINVAL;
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,12 +194,16 @@ POSIX_getenv(int *errno, const char *name)
|
||||||
return e->value;
|
return e->value;
|
||||||
|
|
||||||
e = malloc(sizeof(EnvVar));
|
e = malloc(sizeof(EnvVar));
|
||||||
|
if(e == nil){
|
||||||
|
*errnop = PosixEINVAL;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
e->next = nil;
|
e->next = nil;
|
||||||
e->value = nil; // see free_env
|
e->value = nil; // see free_env
|
||||||
e->name = strdup(name);
|
e->name = strdup(name);
|
||||||
if(e->name == nil){
|
if(e->name == nil){
|
||||||
free_env(e);
|
free_env(e);
|
||||||
*errno = PosixENOMEM;
|
*errnop = PosixEINVAL;
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
e->value = getenv(name);
|
e->value = getenv(name);
|
||||||
|
|
|
@ -132,6 +132,39 @@ get_posix_error(PosixErrorMap *translations, char *err, uintptr_t caller)
|
||||||
return PosixEINVAL;
|
return PosixEINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PosixError
|
||||||
|
libposix_translate_kernel_errors(const char *msg)
|
||||||
|
{
|
||||||
|
// TODO: autogenerate from /sys/src/sysconf.json
|
||||||
|
if(nil == msg)
|
||||||
|
return 0;
|
||||||
|
if(strncmp("interrupted", msg, 9) == 0)
|
||||||
|
return PosixEINTR;
|
||||||
|
if(strncmp("no living children", msg, 18) == 0)
|
||||||
|
return PosixECHILD;
|
||||||
|
if(strstr(msg, "file not found") != nil)
|
||||||
|
return PosixENOENT;
|
||||||
|
if(strstr(msg, "does not exist") != nil)
|
||||||
|
return PosixENOENT;
|
||||||
|
if(strstr(msg, "file already exists") != nil)
|
||||||
|
return PosixEEXIST;
|
||||||
|
if(strstr(msg, "file is a directory") != nil)
|
||||||
|
return PosixEISDIR;
|
||||||
|
if(strncmp("fd out of range or not open", msg, 27) == 0)
|
||||||
|
return PosixEBADF;
|
||||||
|
if(strstr(msg, "not a directory") != nil)
|
||||||
|
return PosixENOTDIR;
|
||||||
|
if(strstr(msg, "permission denied") != nil)
|
||||||
|
return PosixEPERM;
|
||||||
|
if(strstr(msg, "name too long") != nil)
|
||||||
|
return PosixENAMETOOLONG;
|
||||||
|
if(strcmp("i/o error", msg) == 0)
|
||||||
|
return PosixEIO;
|
||||||
|
if(strcmp("i/o on hungup channel", msg) == 0)
|
||||||
|
return PosixEIO;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
__libposix_translate_errstr(uintptr_t caller)
|
__libposix_translate_errstr(uintptr_t caller)
|
||||||
{
|
{
|
||||||
|
@ -153,6 +186,8 @@ __libposix_translate_errstr(uintptr_t caller)
|
||||||
perr = get_posix_error(handler->head, err, caller);
|
perr = get_posix_error(handler->head, err, caller);
|
||||||
if(perr == 0)
|
if(perr == 0)
|
||||||
perr = get_posix_error(generic_handlers, err, caller);
|
perr = get_posix_error(generic_handlers, err, caller);
|
||||||
|
if(perr == 0)
|
||||||
|
perr = libposix_translate_kernel_errors(err);
|
||||||
ret = __libposix_get_errno(perr);
|
ret = __libposix_get_errno(perr);
|
||||||
sys_errstr(err, ERRMAX);
|
sys_errstr(err, ERRMAX);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -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_W_OK;
|
||||||
static int __libposix_X_OK;
|
static int __libposix_X_OK;
|
||||||
|
|
||||||
|
static int *__libposix_coe_fds;
|
||||||
|
static int __libposix_coe_fds_size;
|
||||||
|
static int __libposix_coe_fds_used;
|
||||||
|
|
||||||
typedef enum SeekTypes
|
typedef enum SeekTypes
|
||||||
{
|
{
|
||||||
SeekSet = 0,
|
SeekSet = 0,
|
||||||
|
@ -48,6 +52,71 @@ __libposix_files_check_conf(void)
|
||||||
sysfatal("libposix: no seek translations");
|
sysfatal("libposix: no seek translations");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
__libposix_set_close_on_exec(int fd, int close)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if(__libposix_coe_fds_size == __libposix_coe_fds_used){
|
||||||
|
__libposix_coe_fds_size += 8;
|
||||||
|
__libposix_coe_fds = realloc(__libposix_coe_fds, __libposix_coe_fds_size * sizeof(int));
|
||||||
|
i = __libposix_coe_fds_size;
|
||||||
|
while(i > __libposix_coe_fds_used)
|
||||||
|
__libposix_coe_fds[--i] = -1;
|
||||||
|
}
|
||||||
|
/* remove fd if already present */
|
||||||
|
i = 0;
|
||||||
|
while(i < __libposix_coe_fds_size){
|
||||||
|
if(__libposix_coe_fds[i] == fd){
|
||||||
|
__libposix_coe_fds[i] = -1;
|
||||||
|
--__libposix_coe_fds_used;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
if(close){
|
||||||
|
/* add fd to close on exec */
|
||||||
|
i = 0;
|
||||||
|
while(i < __libposix_coe_fds_size){
|
||||||
|
if(__libposix_coe_fds[i] == -1){
|
||||||
|
__libposix_coe_fds[i] = fd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
++__libposix_coe_fds_used;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
__libposix_close_on_exec(void)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while(i < __libposix_coe_fds_size){
|
||||||
|
if(__libposix_coe_fds[i] != -1){
|
||||||
|
close(__libposix_coe_fds[i]);
|
||||||
|
__libposix_coe_fds[i] = -1;
|
||||||
|
--__libposix_coe_fds_used;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
assert(__libposix_coe_fds_used == 0);
|
||||||
|
free(__libposix_coe_fds);
|
||||||
|
__libposix_coe_fds = nil;
|
||||||
|
__libposix_coe_fds_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
__libposix_should_close_on_exec(int fd)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while(i < __libposix_coe_fds_size){
|
||||||
|
if(__libposix_coe_fds[i] == fd)
|
||||||
|
return 1;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
libposix_translate_open(PosixOpenTranslator translation)
|
libposix_translate_open(PosixOpenTranslator translation)
|
||||||
{
|
{
|
||||||
|
@ -746,6 +815,8 @@ libposix_getdents(int *errnop, int fd, char *buf, int buf_bytes)
|
||||||
goto FailWithENOTDIR; /* not a directory */
|
goto FailWithENOTDIR; /* not a directory */
|
||||||
|
|
||||||
r = read(fd, buf, buf_bytes);
|
r = read(fd, buf, buf_bytes);
|
||||||
|
if(r == 0)
|
||||||
|
return 0;
|
||||||
if(r < 0)
|
if(r < 0)
|
||||||
goto FailWithENOENT; /* removed? */
|
goto FailWithENOENT; /* removed? */
|
||||||
if(r < MINSTATLEN)
|
if(r < MINSTATLEN)
|
||||||
|
|
|
@ -21,70 +21,83 @@
|
||||||
#include <posix.h>
|
#include <posix.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
int group;
|
||||||
|
char raw[sizeof(int)];
|
||||||
|
} IntBuf;
|
||||||
|
|
||||||
|
extern int *__libposix_devsignal;
|
||||||
int __libposix_session_leader = -1;
|
int __libposix_session_leader = -1;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
get_noteid(int *errnop, int pid)
|
get_ppid(int pid)
|
||||||
{
|
{
|
||||||
int n, f;
|
long n;
|
||||||
char buf[30];
|
char buf[32];
|
||||||
sprint(buf, "/proc/%d/noteid", pid);
|
sprint(buf, "/proc/%d/ppid", pid);
|
||||||
f = open(buf, OREAD);
|
n = remove(buf);
|
||||||
if(f < 0){
|
if(n == -1)
|
||||||
*errnop = __libposix_get_errno(PosixEPERM);
|
|
||||||
return -1;
|
return -1;
|
||||||
|
return (int)n;
|
||||||
}
|
}
|
||||||
n = read(f, buf, sizeof(buf) - 1);
|
|
||||||
if(n < 0){
|
|
||||||
*errnop = __libposix_get_errno(PosixEPERM);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
buf[n] = '\0';
|
|
||||||
n = atoi(buf);
|
|
||||||
close(f);
|
|
||||||
|
|
||||||
return n;
|
long
|
||||||
|
__libposix_sighelper_set_pgid(int target, int group)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
PosixHelperRequest request;
|
||||||
|
long raw;
|
||||||
|
} offset;
|
||||||
|
IntBuf buf;
|
||||||
|
|
||||||
|
offset.request.command = PHSetProcessGroup;
|
||||||
|
offset.request.target = target;
|
||||||
|
|
||||||
|
buf.group = group;
|
||||||
|
return pwrite(*__libposix_devsignal, buf.raw, sizeof(buf.raw), offset.raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
set_noteid(int *errnop, int pid, int noteid)
|
set_group_id(int *errnop, int pid, int group)
|
||||||
{
|
{
|
||||||
int n, f;
|
int mypid, ppid;
|
||||||
char buf[30];
|
|
||||||
|
|
||||||
if(pid == 0)
|
if(pid < 0 || group < 0){
|
||||||
pid = getpid();
|
*errnop = __libposix_get_errno(PosixEINVAL);
|
||||||
if(noteid == 0){
|
|
||||||
noteid = get_noteid(errnop, pid);
|
|
||||||
if(noteid < 0)
|
|
||||||
return noteid;
|
|
||||||
}
|
|
||||||
sprint(buf, "/proc/%d/noteid", pid);
|
|
||||||
f = open(buf, OWRITE);
|
|
||||||
if(f < 0) {
|
|
||||||
*errnop = __libposix_get_errno(PosixESRCH);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
n = sprint(buf, "%d", noteid);
|
if(pid == __libposix_session_leader){
|
||||||
n = write(f, buf, n);
|
|
||||||
if(n < 0){
|
|
||||||
*errnop = __libposix_get_errno(PosixEPERM);
|
*errnop = __libposix_get_errno(PosixEPERM);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
close(f);
|
mypid = *__libposix_pid;
|
||||||
return 0;
|
if(pid == 0 && group == 0){
|
||||||
|
/* the caller wants a new process group */
|
||||||
|
CreateNewProcessGroup:
|
||||||
|
rfork(RFNOTEG);
|
||||||
|
return __libposix_sighelper_cmd(PHSetProcessGroup, mypid);
|
||||||
|
}
|
||||||
|
ppid = get_ppid(pid);
|
||||||
|
if(ppid == -1 || pid != mypid && mypid != ppid){
|
||||||
|
*errnop = __libposix_get_errno(PosixESRCH);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(pid == group && pid == mypid)
|
||||||
|
goto CreateNewProcessGroup;
|
||||||
|
|
||||||
|
return __libposix_sighelper_set_pgid(pid, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
POSIX_getuid(int *errnop)
|
POSIX_getuid(int *errnop)
|
||||||
{
|
{
|
||||||
return 0;
|
return 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
POSIX_geteuid(int *errnop)
|
POSIX_geteuid(int *errnop)
|
||||||
{
|
{
|
||||||
return 0;
|
return 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -102,7 +115,7 @@ POSIX_seteuid(int *errnop, int euid)
|
||||||
int
|
int
|
||||||
POSIX_setreuid(int *errnop, int ruid, int euid)
|
POSIX_setreuid(int *errnop, int ruid, int euid)
|
||||||
{
|
{
|
||||||
return 0;
|
return 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -138,61 +151,129 @@ POSIX_setregid(int *errnop, int rgid, int egid)
|
||||||
int
|
int
|
||||||
POSIX_getpgrp(int *errnop)
|
POSIX_getpgrp(int *errnop)
|
||||||
{
|
{
|
||||||
int pid = getpid();
|
long ret;
|
||||||
return get_noteid(errnop, pid);
|
int pid = *__libposix_pid;
|
||||||
|
ret = __libposix_sighelper_cmd(PHGetProcessGroupId, pid);
|
||||||
|
if(ret < 0)
|
||||||
|
return pid;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
POSIX_getpgid(int *errnop, int pid)
|
POSIX_getpgid(int *errnop, int pid)
|
||||||
{
|
{
|
||||||
return get_noteid(errnop, pid);
|
long ret;
|
||||||
|
ret = __libposix_sighelper_cmd(PHGetProcessGroupId, pid);
|
||||||
|
if(ret < 0)
|
||||||
|
*errnop = __libposix_get_errno(PosixESRCH);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
POSIX_setpgid(int *errnop, int pid, int pgid)
|
POSIX_setpgid(int *errnop, int pid, int pgid)
|
||||||
{
|
{
|
||||||
if(pid < 0 || pgid < 0){
|
return set_group_id(errnop, pid, pgid);
|
||||||
*errnop = __libposix_get_errno(PosixEINVAL);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return set_noteid(errnop, pid, pgid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
POSIX_getsid(int *errnop, int pid)
|
POSIX_getsid(int *errnop, int pid)
|
||||||
{
|
{
|
||||||
int reqnoteid, mynoteid;
|
int mypid;
|
||||||
|
long sid;
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
if(pid < 0){
|
if(pid < 0){
|
||||||
|
FailWithESRCH:
|
||||||
*errnop = __libposix_get_errno(PosixESRCH);
|
*errnop = __libposix_get_errno(PosixESRCH);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
snprint(buf, sizeof(buf), "/proc/%d/ns", pid);
|
||||||
|
if(access(buf, AEXIST) != 0)
|
||||||
|
goto FailWithESRCH;
|
||||||
|
|
||||||
|
mypid = *__libposix_pid;
|
||||||
if(pid == 0)
|
if(pid == 0)
|
||||||
pid = getpid();
|
pid = mypid;
|
||||||
else if(pid == getpid())
|
sid = __libposix_sighelper_cmd(PHGetSessionId, pid);
|
||||||
return __libposix_session_leader;
|
if(sid < 0){
|
||||||
reqnoteid = get_noteid(errnop, pid);
|
*errnop = __libposix_get_errno(PosixEPERM);
|
||||||
if(reqnoteid < 0)
|
return -1;
|
||||||
return reqnoteid;
|
|
||||||
if(__libposix_session_leader < 0)
|
|
||||||
return reqnoteid;
|
|
||||||
mynoteid = POSIX_getpgrp(errnop);
|
|
||||||
if(mynoteid == reqnoteid){
|
|
||||||
/* if it share our pgrp (aka noteid), it shares
|
|
||||||
* our session leader
|
|
||||||
*/
|
|
||||||
return __libposix_session_leader;
|
|
||||||
}
|
}
|
||||||
return reqnoteid;
|
if(pid == mypid)
|
||||||
|
__libposix_session_leader = (int)sid;
|
||||||
|
|
||||||
|
return sid;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
POSIX_setsid(int *errnop)
|
POSIX_setsid(int *errnop)
|
||||||
{
|
{
|
||||||
if(rfork(RFNAMEG|RFNOTEG) < 0){
|
extern PosixSignalMask *__libposix_signal_mask;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
*errnop = __libposix_get_errno(PosixEPERM);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
__libposix_session_leader = POSIX_getpgrp(errnop);
|
|
||||||
return __libposix_session_leader;
|
|
||||||
}
|
|
||||||
|
|
|
@ -24,11 +24,12 @@ extern int *__libposix_errors_codes;
|
||||||
extern WaitList **__libposix_wait_list;
|
extern WaitList **__libposix_wait_list;
|
||||||
extern ChildList **__libposix_child_list;
|
extern ChildList **__libposix_child_list;
|
||||||
static int __initialized;
|
static int __initialized;
|
||||||
static unsigned char signals_to_code[256];
|
static PosixProcessDisposer __libposix_process_dispose;
|
||||||
static unsigned char code_to_signal[256];
|
|
||||||
|
|
||||||
|
int *__libposix_sigchld_father_pid;
|
||||||
int *__libposix_sigchld_target_pid;
|
int *__libposix_sigchld_child_pid;
|
||||||
|
int *__libposix_devsignal;
|
||||||
|
int *__libposix_pid;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
libposix_check_configuration(void)
|
libposix_check_configuration(void)
|
||||||
|
@ -36,29 +37,45 @@ libposix_check_configuration(void)
|
||||||
__libposix_errors_check_conf();
|
__libposix_errors_check_conf();
|
||||||
__libposix_files_check_conf();
|
__libposix_files_check_conf();
|
||||||
__libposix_processes_check_conf();
|
__libposix_processes_check_conf();
|
||||||
__libposix_signal_check_conf();
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
__libposix_sighelper_open(void)
|
||||||
|
{
|
||||||
|
int mypid;
|
||||||
|
if(*__libposix_devsignal >= 0)
|
||||||
|
close(*__libposix_devsignal);
|
||||||
|
mypid = *__libposix_pid;
|
||||||
|
*__libposix_devsignal = create("/dev/posix/signals", ORDWR|OCEXEC, mypid);
|
||||||
|
if(*__libposix_devsignal < 0)
|
||||||
|
sysfatal("cannot create /dev/posix/signals: %r");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
libposix_init(int argc, char *argv[], PosixInit init)
|
libposix_init(int argc, char *argv[], PosixInit init)
|
||||||
{
|
{
|
||||||
extern int main(int, char**);
|
extern int main(int, char**);
|
||||||
extern unsigned char *__signals_to_code_map;
|
|
||||||
extern unsigned char *__code_to_signal_map;
|
|
||||||
extern int *__handling_external_signal;
|
extern int *__handling_external_signal;
|
||||||
extern int *__restart_syscall;
|
extern int *__restart_syscall;
|
||||||
extern int *__libposix_sigchld_target_pid;
|
extern PosixSignalMask *__libposix_signal_mask;
|
||||||
|
|
||||||
WaitList *wait_list;
|
WaitList *wait_list;
|
||||||
ChildList *child_list;
|
ChildList *child_list;
|
||||||
|
PosixSignalMask signal_mask;
|
||||||
|
int mypid;
|
||||||
int status;
|
int status;
|
||||||
int error_codes[ERRNO_LAST-ERRNO_FIRST];
|
int error_codes[ERRNO_LAST-ERRNO_FIRST];
|
||||||
int handling_signal;
|
int handling_signal;
|
||||||
int sigchld_target_pid;
|
int sigchld_father_pid;
|
||||||
|
int sigchld_child_pid;
|
||||||
int restart_syscall;
|
int restart_syscall;
|
||||||
|
int devsignal;
|
||||||
|
|
||||||
assert(__initialized == 0);
|
assert(__initialized == 0);
|
||||||
|
|
||||||
|
mypid = getpid();
|
||||||
|
__libposix_pid = &mypid;
|
||||||
|
|
||||||
/* initialize PosixErrors map */
|
/* initialize PosixErrors map */
|
||||||
memset(error_codes, 0, sizeof(error_codes));
|
memset(error_codes, 0, sizeof(error_codes));
|
||||||
__libposix_errors_codes = error_codes;
|
__libposix_errors_codes = error_codes;
|
||||||
|
@ -72,28 +89,63 @@ libposix_init(int argc, char *argv[], PosixInit init)
|
||||||
__libposix_child_list = &child_list;
|
__libposix_child_list = &child_list;
|
||||||
|
|
||||||
/* initialize signal handling */
|
/* initialize signal handling */
|
||||||
restart_syscall = 0;
|
|
||||||
handling_signal = 0;
|
handling_signal = 0;
|
||||||
sigchld_target_pid = 0;
|
sigchld_father_pid = 0;
|
||||||
|
sigchld_child_pid = 0;
|
||||||
|
signal_mask = 0;
|
||||||
|
devsignal = -1;
|
||||||
|
__libposix_devsignal = &devsignal;
|
||||||
__restart_syscall = &restart_syscall;
|
__restart_syscall = &restart_syscall;
|
||||||
__signals_to_code_map = signals_to_code;
|
|
||||||
__code_to_signal_map = code_to_signal;
|
|
||||||
__handling_external_signal = &handling_signal;
|
__handling_external_signal = &handling_signal;
|
||||||
__libposix_sigchld_target_pid = &sigchld_target_pid;
|
__libposix_sigchld_father_pid = &sigchld_father_pid;
|
||||||
|
__libposix_sigchld_child_pid = &sigchld_child_pid;
|
||||||
|
__libposix_signal_mask = &signal_mask;
|
||||||
|
__libposix_reset_pending_signals();
|
||||||
if(!atnotify(__libposix_note_handler, 1))
|
if(!atnotify(__libposix_note_handler, 1))
|
||||||
sysfatal("libposix: atnotify");
|
sysfatal("libposix: atnotify");
|
||||||
|
|
||||||
init();
|
__libposix_sighelper_open();
|
||||||
|
signal_mask = (PosixSignalMask)__libposix_sighelper_cmd(PHGetProcMask, 0);
|
||||||
|
__libposix_init_signal_handlers();
|
||||||
|
|
||||||
|
init(argc, argv);
|
||||||
|
|
||||||
libposix_check_configuration();
|
libposix_check_configuration();
|
||||||
|
|
||||||
__initialized = 1;
|
__initialized = 1;
|
||||||
status = main(argc, argv);
|
status = main(argc, argv);
|
||||||
|
|
||||||
|
if(__libposix_process_dispose != nil)
|
||||||
|
__libposix_process_dispose(status);
|
||||||
|
|
||||||
POSIX_exit(status);
|
POSIX_exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
libposix_on_process_disposition(PosixProcessDisposer dispose)
|
||||||
|
{
|
||||||
|
if(__libposix_process_dispose != nil)
|
||||||
|
return 0;
|
||||||
|
__libposix_process_dispose = dispose;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
__libposix_initialized(void)
|
__libposix_initialized(void)
|
||||||
{
|
{
|
||||||
return __initialized;
|
return __initialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long
|
||||||
|
__libposix_sighelper_cmd(PosixHelperCommand command, int posix_process_pid)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
PosixHelperRequest request;
|
||||||
|
long raw;
|
||||||
|
} offset;
|
||||||
|
|
||||||
|
offset.request.command = command;
|
||||||
|
offset.request.target = posix_process_pid;
|
||||||
|
|
||||||
|
return pwrite(*__libposix_devsignal, "", 0, offset.raw);
|
||||||
|
}
|
||||||
|
|
|
@ -33,10 +33,29 @@ struct ChildList
|
||||||
ChildList *next;
|
ChildList *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct SignalConf SignalConf;
|
||||||
|
struct SignalConf
|
||||||
|
{
|
||||||
|
void* handler;
|
||||||
|
PosixSignalMask mask : 56;
|
||||||
|
int sa_siginfo : 1;
|
||||||
|
int sa_resethand : 1;
|
||||||
|
int sa_restart : 1;
|
||||||
|
int sa_nochildwait : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct PendingSignalList PendingSignalList;
|
||||||
|
struct PendingSignalList
|
||||||
|
{
|
||||||
|
PosixSignalInfo signal;
|
||||||
|
PendingSignalList* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int *__libposix_pid;
|
||||||
|
|
||||||
extern void __libposix_files_check_conf(void);
|
extern void __libposix_files_check_conf(void);
|
||||||
extern void __libposix_errors_check_conf(void);
|
extern void __libposix_errors_check_conf(void);
|
||||||
extern void __libposix_processes_check_conf(void);
|
extern void __libposix_processes_check_conf(void);
|
||||||
extern void __libposix_signal_check_conf(void);
|
|
||||||
extern int __libposix_initialized(void);
|
extern int __libposix_initialized(void);
|
||||||
|
|
||||||
extern int __libposix_get_errno(PosixError e);
|
extern int __libposix_get_errno(PosixError e);
|
||||||
|
@ -51,16 +70,75 @@ extern void __libposix_free_wait_list(void);
|
||||||
|
|
||||||
extern void __libposix_setup_new_process(void);
|
extern void __libposix_setup_new_process(void);
|
||||||
|
|
||||||
extern int __libposix_note_to_signal(char *note);
|
extern int __libposix_signal_to_note(const PosixSignalInfo *si, char *buf, int size);
|
||||||
|
|
||||||
|
extern int __libposix_note_to_signal(const char *note, PosixSignalInfo *siginfo);
|
||||||
|
|
||||||
extern int __libposix_is_child(int pid);
|
extern int __libposix_is_child(int pid);
|
||||||
|
|
||||||
|
extern void __libposix_free_child_list(void);
|
||||||
|
|
||||||
extern void __libposix_forget_child(int pid);
|
extern void __libposix_forget_child(int pid);
|
||||||
|
|
||||||
extern int __libposix_send_control_msg(int pid, char *msg);
|
extern int __libposix_send_control_msg(int pid, char *msg);
|
||||||
|
|
||||||
extern PosixError __libposix_notify_signal_to_process(int pid, int signal);
|
extern PosixError __libposix_notify_signal_to_process(int pid, PosixSignalInfo *siginfo);
|
||||||
|
|
||||||
extern PosixError __libposix_receive_signal(int sig);
|
extern PosixError __libposix_receive_signal(PosixSignalInfo *siginfo);
|
||||||
|
|
||||||
|
extern PosixError __libposix_dispatch_signal(int pid, PosixSignalInfo* siginfo);
|
||||||
|
|
||||||
extern int __libposix_restart_syscall(void);
|
extern int __libposix_restart_syscall(void);
|
||||||
|
|
||||||
|
extern int __libposix_signal_blocked(PosixSignalInfo *siginfo);
|
||||||
|
|
||||||
|
extern int __libposix_run_signal_handler(SignalConf *c, PosixSignalInfo *siginfo);
|
||||||
|
|
||||||
|
extern void __libposix_reset_pending_signals(void);
|
||||||
|
|
||||||
|
extern void __libposix_set_close_on_exec(int fd, int close);
|
||||||
|
|
||||||
|
extern int __libposix_should_close_on_exec(int fd);
|
||||||
|
|
||||||
|
extern void __libposix_close_on_exec(void);
|
||||||
|
|
||||||
|
extern void __libposix_init_signal_handlers(void);
|
||||||
|
|
||||||
|
#define SIGNAL_MASK(signal) (1ULL<<((signal)-1))
|
||||||
|
#define SIGNAL_RAW_ADD(bitmask, signal) (bitmask |= SIGNAL_MASK(signal))
|
||||||
|
#define SIGNAL_RAW_DEL(bitmask, signal) (bitmask &= ~SIGNAL_MASK(signal))
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PHProcessExited, /* WRITE, for nannies, the child might not be a libposix application */
|
||||||
|
PHCallingExec, /* WRITE */
|
||||||
|
|
||||||
|
PHSignalProcess, /* WRITE */
|
||||||
|
PHSignalGroup, /* WRITE */
|
||||||
|
PHSignalForeground, /* WRITE, for the controller process */
|
||||||
|
|
||||||
|
PHIgnoreSignal, /* WRITE */
|
||||||
|
PHEnableSignal, /* WRITE */
|
||||||
|
PHBlockSignals, /* WRITE */
|
||||||
|
PHWaitSignals, /* READ, may block */
|
||||||
|
|
||||||
|
PHGetSessionId, /* WRITE, ret contains the id */
|
||||||
|
PHGetProcessGroupId, /* WRITE, ret contains the id */
|
||||||
|
PHGetPendingSignals, /* WRITE, ret contains the mask */
|
||||||
|
PHGetProcMask, /* WRITE, ret contains the mask */
|
||||||
|
|
||||||
|
PHSetForegroundGroup, /* WRITE */
|
||||||
|
PHGetForegroundGroup, /* WRITE */
|
||||||
|
PHDetachSession, /* WRITE */
|
||||||
|
PHSetProcessGroup, /* WRITE */
|
||||||
|
} PosixHelperCommand;
|
||||||
|
typedef struct {
|
||||||
|
int target;
|
||||||
|
PosixHelperCommand command;
|
||||||
|
} PosixHelperRequest;
|
||||||
|
|
||||||
|
extern void __libposix_sighelper_open(void);
|
||||||
|
extern long __libposix_sighelper_cmd(PosixHelperCommand command, int target);
|
||||||
|
extern long __libposix_sighelper_set(PosixHelperCommand command, PosixSignalMask signal_set);
|
||||||
|
extern long __libposix_sighelper_signal(PosixHelperCommand command, int target, PosixSignalInfo *siginfo);
|
||||||
|
extern long __libposix_sighelper_wait(PosixSignalMask set, PosixSignalInfo *siginfo);
|
||||||
|
extern long __libposix_sighelper_set_pgid(int target, int group_id);
|
||||||
|
|
|
@ -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);
|
l = strlen(buf);
|
||||||
if(l >= 9 && strcmp(buf+l-9, "/dev/cons") == 0)
|
if((l >= 9 && strcmp(buf+l-9, "/dev/cons") == 0)
|
||||||
|
||(l >= 8 && strcmp(buf+l-8, "/dev/tty") == 0))
|
||||||
return 1;
|
return 1;
|
||||||
*errnop = __libposix_get_errno(PosixENOTTY);
|
*errnop = __libposix_get_errno(PosixENOTTY);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -138,12 +139,14 @@ POSIX_getpass(int *errnop, const char *prompt)
|
||||||
char *p;
|
char *p;
|
||||||
static char buf[256];
|
static char buf[256];
|
||||||
|
|
||||||
if(fd2path(0, buf, sizeof(buf)) == 0 && strcmp("/dev/cons", buf) == 0)
|
if(fd2path(0, buf, sizeof(buf)) == 0
|
||||||
|
&& (strcmp("/dev/cons", buf) == 0 || strcmp("/dev/tty", buf) == 0))
|
||||||
r = 0;
|
r = 0;
|
||||||
else if((r = open("/dev/cons", OREAD)) < 0)
|
else if((r = open("/dev/cons", OREAD)) < 0)
|
||||||
goto ReturnENXIO;
|
goto ReturnENXIO;
|
||||||
|
|
||||||
if(fd2path(1, buf, sizeof(buf)) == 0 && strcmp("/dev/cons", buf) == 0)
|
if(fd2path(1, buf, sizeof(buf)) == 0
|
||||||
|
&& (strcmp("/dev/cons", buf) == 0 || strcmp("/dev/tty", buf) == 0))
|
||||||
w = 1;
|
w = 1;
|
||||||
else if((w = open("/dev/cons", OWRITE)) < 0)
|
else if((w = open("/dev/cons", OWRITE)) < 0)
|
||||||
goto CloseRAndReturnENXIO;
|
goto CloseRAndReturnENXIO;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -55,39 +55,29 @@ int (*__libposix_fork)(int *errnop) = fork_without_sigchld;
|
||||||
void
|
void
|
||||||
__libposix_free_wait_list(void)
|
__libposix_free_wait_list(void)
|
||||||
{
|
{
|
||||||
WaitList *wl, *c;
|
WaitList *tail, *w;
|
||||||
|
|
||||||
/* free the wait list as the memory is NOT shared */
|
/* free the wait list as the memory is NOT shared */
|
||||||
wl = *__libposix_wait_list;
|
tail = *__libposix_wait_list;
|
||||||
if(wl != nil){
|
while(w = tail){
|
||||||
|
tail = tail->next;
|
||||||
|
free(w);
|
||||||
|
}
|
||||||
*__libposix_wait_list = nil;
|
*__libposix_wait_list = nil;
|
||||||
do
|
|
||||||
{
|
|
||||||
c = wl;
|
|
||||||
wl = c->next;
|
|
||||||
free(c);
|
|
||||||
}
|
|
||||||
while (wl != nil);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
__libposix_free_child_list(void)
|
__libposix_free_child_list(void)
|
||||||
{
|
{
|
||||||
ChildList *l, *c;
|
ChildList *tail, *c;
|
||||||
|
|
||||||
/* free the wait list as the memory is shared */
|
/* free the wait list as the memory is shared */
|
||||||
l = *__libposix_child_list;
|
tail = *__libposix_child_list;
|
||||||
if(l != nil){
|
while(c = tail){
|
||||||
*__libposix_child_list = nil;
|
tail = tail->next;
|
||||||
do
|
|
||||||
{
|
|
||||||
c = l;
|
|
||||||
l = c->next;
|
|
||||||
free(c);
|
free(c);
|
||||||
}
|
}
|
||||||
while (l != nil);
|
*__libposix_child_list = nil;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -112,8 +102,7 @@ __libposix_forget_child(int pid)
|
||||||
|
|
||||||
/* free the wait list as the memory is shared */
|
/* free the wait list as the memory is shared */
|
||||||
l = __libposix_child_list;
|
l = __libposix_child_list;
|
||||||
while(*l != nil){
|
while(c = *l){
|
||||||
c = *l;
|
|
||||||
if(c->pid == pid){
|
if(c->pid == pid){
|
||||||
*l = c->next;
|
*l = c->next;
|
||||||
free(c);
|
free(c);
|
||||||
|
@ -126,9 +115,18 @@ __libposix_forget_child(int pid)
|
||||||
void
|
void
|
||||||
__libposix_setup_new_process(void)
|
__libposix_setup_new_process(void)
|
||||||
{
|
{
|
||||||
|
extern PosixSignalMask *__libposix_signal_mask;
|
||||||
|
|
||||||
|
*__libposix_pid = getpid();
|
||||||
|
|
||||||
/* reset wait list for the child */
|
/* reset wait list for the child */
|
||||||
__libposix_free_wait_list();
|
__libposix_free_wait_list();
|
||||||
__libposix_free_child_list();
|
__libposix_free_child_list();
|
||||||
|
|
||||||
|
/* clear pending signals; reload mask */
|
||||||
|
__libposix_reset_pending_signals();
|
||||||
|
__libposix_sighelper_open();
|
||||||
|
*__libposix_signal_mask = (PosixSignalMask)__libposix_sighelper_cmd(PHGetProcMask, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -178,8 +176,6 @@ POSIX_getrusage(int *errnop, PosixRUsages who, void *r_usagep)
|
||||||
int
|
int
|
||||||
POSIX_execve(int *errnop, const char *name, char * const*argv, char * const*env)
|
POSIX_execve(int *errnop, const char *name, char * const*argv, char * const*env)
|
||||||
{
|
{
|
||||||
long ret;
|
|
||||||
|
|
||||||
// see http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
|
// see http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
|
||||||
if(env == environ){
|
if(env == environ){
|
||||||
/* just get a copy of the current environment */
|
/* just get a copy of the current environment */
|
||||||
|
@ -190,25 +186,18 @@ POSIX_execve(int *errnop, const char *name, char * const*argv, char * const*env)
|
||||||
}
|
}
|
||||||
|
|
||||||
__libposix_free_wait_list();
|
__libposix_free_wait_list();
|
||||||
|
__libposix_close_on_exec();
|
||||||
|
__libposix_sighelper_cmd(PHCallingExec, 0);
|
||||||
|
|
||||||
ret = sys_exec(name, argv);
|
sys_exec(name, argv);
|
||||||
switch(ret){
|
|
||||||
case 0:
|
|
||||||
return 0;
|
|
||||||
case ~0:
|
|
||||||
*errnop = __libposix_translate_errstr((uintptr_t)POSIX_execve);
|
*errnop = __libposix_translate_errstr((uintptr_t)POSIX_execve);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
*errnop = ret;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
POSIX_getpid(int *errnop)
|
POSIX_getpid(int *errnop)
|
||||||
{
|
{
|
||||||
return getpid();
|
return *__libposix_pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -223,13 +212,14 @@ POSIX_fork(int *errnop)
|
||||||
return __libposix_fork(errnop);
|
return __libposix_fork(errnop);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
POSIX_wait(int *errnop, int *status)
|
__libposix_wait(int *errnop, int *status, long ms)
|
||||||
{
|
{
|
||||||
Waitmsg *w;
|
Waitmsg *w;
|
||||||
WaitList *l;
|
WaitList *l;
|
||||||
char *s;
|
char *s, err[ERRMAX];
|
||||||
int ret = 0, sig = 0, pid;
|
int ret = 0, sig = 0, pid;
|
||||||
|
long wakeup = 0;
|
||||||
|
|
||||||
l = *__libposix_wait_list;
|
l = *__libposix_wait_list;
|
||||||
if(l != nil){
|
if(l != nil){
|
||||||
|
@ -242,10 +232,25 @@ POSIX_wait(int *errnop, int *status)
|
||||||
}
|
}
|
||||||
|
|
||||||
OnIgnoredSignalInterrupt:
|
OnIgnoredSignalInterrupt:
|
||||||
|
if(ms)
|
||||||
|
wakeup = awake(ms);
|
||||||
w = wait();
|
w = wait();
|
||||||
if(w == nil){
|
if(w == nil){
|
||||||
if(__libposix_restart_syscall())
|
rerrstr(err, ERRMAX);
|
||||||
|
if(strstr(err, "no living children") != nil){
|
||||||
|
*errnop = __libposix_get_errno(PosixECHILD);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(__libposix_restart_syscall()){
|
||||||
|
if(wakeup)
|
||||||
|
forgivewkp(wakeup);
|
||||||
goto OnIgnoredSignalInterrupt;
|
goto OnIgnoredSignalInterrupt;
|
||||||
|
}
|
||||||
|
if(wakeup){
|
||||||
|
if(awakened(wakeup))
|
||||||
|
return 0;
|
||||||
|
forgivewkp(wakeup);
|
||||||
|
}
|
||||||
*errnop = __libposix_get_errno(PosixECHILD);
|
*errnop = __libposix_get_errno(PosixECHILD);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -283,13 +288,20 @@ POSIX_umask(int *errnop, int mask)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
POSIX_wait(int *errnop, int *status)
|
||||||
|
{
|
||||||
|
return __libposix_wait(errnop, status, 0);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
POSIX_waitpid(int *errnop, int reqpid, int *status, int options)
|
POSIX_waitpid(int *errnop, int reqpid, int *status, int options)
|
||||||
{
|
{
|
||||||
Waitmsg *w;
|
Waitmsg *w;
|
||||||
WaitList *c, **nl;
|
WaitList *c, **nl;
|
||||||
char *s;
|
char *s, err[ERRMAX];
|
||||||
int ret = 0, sig = 0, nohang = 0, pid;
|
int ret = 0, sig = 0, pid;
|
||||||
|
long nohang = 0;
|
||||||
|
|
||||||
|
|
||||||
if(options & __libposix_wnohang){
|
if(options & __libposix_wnohang){
|
||||||
|
@ -304,10 +316,9 @@ POSIX_waitpid(int *errnop, int reqpid, int *status, int options)
|
||||||
switch(reqpid){
|
switch(reqpid){
|
||||||
case -1:
|
case -1:
|
||||||
if(nohang){
|
if(nohang){
|
||||||
*errnop = __libposix_get_errno(PosixEINVAL);
|
return __libposix_wait(errnop, status, 100);
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
return POSIX_wait(errnop, status);
|
return __libposix_wait(errnop, status, 0);
|
||||||
case 0:
|
case 0:
|
||||||
/* not yet implemented; requires changes to Waitmsg */
|
/* not yet implemented; requires changes to Waitmsg */
|
||||||
*errnop = __libposix_get_errno(PosixEINVAL);
|
*errnop = __libposix_get_errno(PosixEINVAL);
|
||||||
|
@ -337,13 +348,30 @@ POSIX_waitpid(int *errnop, int reqpid, int *status, int options)
|
||||||
|
|
||||||
WaitAgain:
|
WaitAgain:
|
||||||
OnIgnoredSignalInterrupt:
|
OnIgnoredSignalInterrupt:
|
||||||
|
if(nohang)
|
||||||
|
nohang = awake(100);
|
||||||
w = wait();
|
w = wait();
|
||||||
if(w == nil){
|
if(w == nil){
|
||||||
if(__libposix_restart_syscall())
|
rerrstr(err, ERRMAX);
|
||||||
goto OnIgnoredSignalInterrupt;
|
if(strstr(err, "no living children") != nil){
|
||||||
*errnop = __libposix_get_errno(PosixECHILD);
|
*errnop = __libposix_get_errno(PosixECHILD);
|
||||||
return -1;
|
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;
|
pid = w->pid;
|
||||||
__libposix_forget_child(pid);
|
__libposix_forget_child(pid);
|
||||||
if(w->msg[0] != 0){
|
if(w->msg[0] != 0){
|
||||||
|
|
|
@ -21,61 +21,51 @@
|
||||||
#include <posix.h>
|
#include <posix.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
/* rendezvous points */
|
|
||||||
extern unsigned char *__signals_to_code_map;
|
|
||||||
extern unsigned char *__code_to_signal_map;
|
|
||||||
extern ChildList **__libposix_child_list;
|
|
||||||
|
|
||||||
/* pointer to the pid to forward notes to */
|
/* pointer to the pid to forward notes to */
|
||||||
extern int *__libposix_sigchld_target_pid;
|
extern ChildList **__libposix_child_list;
|
||||||
|
extern WaitList **__libposix_wait_list;
|
||||||
#define CHILD_READY(pid) ((long)rendezvous(&__signals_to_code_map, (void*)(~(pid))))
|
extern SignalConf *__libposix_signals;
|
||||||
#define C2P_READY(pid) ((long)rendezvous(&__code_to_signal_map, (void*)(~(pid))))
|
extern int *__libposix_devsignal;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
release_inherited_resources(void)
|
open_sighelper_nanny(void)
|
||||||
{
|
{
|
||||||
notify(nil);
|
int mypid;
|
||||||
rfork(RFCNAMEG|RFCENVG|RFNOTEG|RFCFDG);
|
if(*__libposix_devsignal >= 0)
|
||||||
bind("#p", "/proc", MREPL);
|
close(*__libposix_devsignal);
|
||||||
rfork(RFNOMNT);
|
mypid = *__libposix_pid;
|
||||||
|
*__libposix_devsignal = create("/dev/posix/nanny", OWRITE|OCEXEC, mypid);
|
||||||
|
if(*__libposix_devsignal < 0)
|
||||||
|
sysfatal("cannot create /dev/posix/nanny: %r");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
forwarding_note_handler(void *ureg, char *note)
|
exit_on_SA_NOCLDWAIT(char *msg){
|
||||||
{
|
/* we share the father's memory, we can inspect its configuration */
|
||||||
extern int __min_known_sig;
|
if(__libposix_signals[PosixSIGCHLD-1].sa_nochildwait){
|
||||||
extern int __max_known_sig;
|
/* the parent does not care about us*/
|
||||||
int sig;
|
rfork(RFNOWAIT);
|
||||||
PosixSignals signal;
|
exits(msg);
|
||||||
if(strncmp(note, __POSIX_SIGNAL_PREFIX, __POSIX_SIGNAL_PREFIX_LEN) == 0){
|
|
||||||
sig = __libposix_note_to_signal(note);
|
|
||||||
if(sig < __min_known_sig || sig > __max_known_sig){
|
|
||||||
/* Ignore unknown signals */
|
|
||||||
noted(NCONT);
|
|
||||||
}
|
|
||||||
signal = __code_to_signal_map[sig];
|
|
||||||
__libposix_notify_signal_to_process(*__libposix_sigchld_target_pid, sig);
|
|
||||||
if(signal == PosixSIGCONT)
|
|
||||||
__libposix_send_control_msg(*__libposix_sigchld_target_pid, "start");
|
|
||||||
noted(NCONT);
|
|
||||||
} else {
|
|
||||||
/* what happened? */
|
|
||||||
noted(NDFLT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
forward_wait_msg(int sigchld_receiver, char *name)
|
forward_wait_msg(int father, int child)
|
||||||
{
|
{
|
||||||
int n;
|
int n, mypid;
|
||||||
char buf[512], err[ERRMAX], note[512], *fld[5];
|
PosixSignalInfo si;
|
||||||
|
char buf[512], err[ERRMAX], note[512], *fld[5], *tmp, *name;
|
||||||
|
|
||||||
snprint(buf, sizeof(buf), "/proc/%d/args", getpid());
|
mypid = *__libposix_pid;
|
||||||
|
name = smprint("signal proxy %d <> %d", father, child);
|
||||||
|
snprint(buf, sizeof(buf), "/proc/%d/args", mypid);
|
||||||
n = open(buf, OWRITE);
|
n = open(buf, OWRITE);
|
||||||
write(n, name, strlen(name)+1);
|
write(n, name, strlen(name)+1);
|
||||||
close(n);
|
close(n);
|
||||||
|
|
||||||
|
rfork(RFCNAMEG|RFCENVG|RFNOMNT);
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
WaitInterrupted:
|
WaitInterrupted:
|
||||||
n = await(buf, sizeof buf-1);
|
n = await(buf, sizeof buf-1);
|
||||||
|
@ -84,21 +74,45 @@ WaitInterrupted:
|
||||||
if(strstr(err, "no living children") == nil)
|
if(strstr(err, "no living children") == nil)
|
||||||
goto WaitInterrupted;
|
goto WaitInterrupted;
|
||||||
snprint(note, sizeof(note), "%s: %r", name);
|
snprint(note, sizeof(note), "%s: %r", name);
|
||||||
if(sigchld_receiver)
|
exit_on_SA_NOCLDWAIT(note);
|
||||||
postnote(PNPROC, sigchld_receiver, note);
|
postnote(PNPROC, father, note);
|
||||||
|
__libposix_sighelper_cmd(PHProcessExited, child);
|
||||||
exits(note);
|
exits(note);
|
||||||
}
|
}
|
||||||
buf[n] = '\0';
|
buf[n] = '\0';
|
||||||
if(jehanne_tokenize(buf, fld, nelem(fld)) != nelem(fld)){
|
if(jehanne_tokenize(buf, fld, nelem(fld)) != nelem(fld)){
|
||||||
snprint(note, sizeof(note), "%s: couldn't parse wait message", name);
|
snprint(note, sizeof(note), "%s: can not parse wait msg: %s", name, buf);
|
||||||
if(sigchld_receiver)
|
exit_on_SA_NOCLDWAIT(note);
|
||||||
postnote(PNPROC, sigchld_receiver, note);
|
postnote(PNPROC, father, note);
|
||||||
exits(note);
|
exits(note);
|
||||||
}
|
}
|
||||||
snprint(note, sizeof(note), __POSIX_SIGNAL_PREFIX " %d", __signals_to_code_map[PosixSIGCHLD]);
|
memset(&si, 0, sizeof(PosixSignalInfo));
|
||||||
if(sigchld_receiver){
|
si.si_pid = mypid;
|
||||||
postnote(PNPROC, sigchld_receiver, note);
|
si.si_signo = PosixSIGCHLD;
|
||||||
}
|
si.si_code = PosixSIChildExited;
|
||||||
|
si.si_uid = POSIX_getuid(&n);
|
||||||
|
tmp = fld[4];
|
||||||
|
if(tmp == nil || tmp[0] == '\0')
|
||||||
|
n = 0;
|
||||||
|
else if(strcmp(__POSIX_EXIT_PREFIX, tmp) == 0)
|
||||||
|
n = atoi(tmp + (sizeof(__POSIX_EXIT_PREFIX)/sizeof(char) - 1));
|
||||||
|
else if(strcmp(__POSIX_EXIT_SIGNAL_PREFIX, tmp) == 0){
|
||||||
|
n = atoi(tmp + (sizeof(__POSIX_EXIT_SIGNAL_PREFIX)/sizeof(char) - 1));
|
||||||
|
if(n == PosixSIGTRAP)
|
||||||
|
si.si_code = PosixSIChildTrapped;
|
||||||
|
else
|
||||||
|
si.si_code = PosixSIChildKilled;
|
||||||
|
} else
|
||||||
|
n = 127;
|
||||||
|
si.si_status = n;
|
||||||
|
|
||||||
|
exit_on_SA_NOCLDWAIT("SIGCHLD explicity ignored by parent");
|
||||||
|
|
||||||
|
__libposix_notify_signal_to_process(father, &si);
|
||||||
|
|
||||||
|
__libposix_sighelper_cmd(PHProcessExited, child);
|
||||||
|
if(n == 0)
|
||||||
|
exits(nil);
|
||||||
exits(fld[4]);
|
exits(fld[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,99 +120,76 @@ WaitInterrupted:
|
||||||
static int
|
static int
|
||||||
fork_with_sigchld(int *errnop)
|
fork_with_sigchld(int *errnop)
|
||||||
{
|
{
|
||||||
int father = getpid();
|
int proxy, father, child = -1;
|
||||||
int p2c;
|
|
||||||
long c2p = -1, child = -1;
|
|
||||||
char proxy_name[256];
|
|
||||||
ChildList *c;
|
ChildList *c;
|
||||||
|
uint64_t rend;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
/* Father here:
|
/* Father here:
|
||||||
* - create P2C
|
* - create proxy
|
||||||
* - wait for C2P to be ready
|
* - wait for child to be ready
|
||||||
* - register P2C in children list
|
* - register proxy in children list
|
||||||
* - return P2C pid
|
* - return proxy pid
|
||||||
*/
|
*/
|
||||||
switch(p2c = rfork(RFPROC|RFMEM)){
|
father = getpid();
|
||||||
|
|
||||||
|
switch(proxy = rfork(RFPROC|RFMEM|RFFDG)){
|
||||||
case -1:
|
case -1:
|
||||||
return -1;
|
return -1;
|
||||||
case 0:
|
case 0:
|
||||||
/* P2C here:
|
/* proxy here:
|
||||||
* - create C2P
|
|
||||||
* - wait for the child pid
|
|
||||||
* - release all inherited resources
|
|
||||||
* - install forwarding_note_handler
|
|
||||||
* - send to father the C2P pid
|
|
||||||
* - start waiting for the child
|
|
||||||
*/
|
|
||||||
switch(c2p = rfork(RFPROC|RFMEM)){
|
|
||||||
case -1:
|
|
||||||
while(C2P_READY(-2) == -1)
|
|
||||||
;
|
|
||||||
exits("rfork (c2p)");
|
|
||||||
case 0:
|
|
||||||
/* C2P here:
|
|
||||||
* - create child
|
* - create child
|
||||||
* - wait for it to get a copy of everything
|
* - start waiting
|
||||||
* - release all inherited resources
|
|
||||||
* - install forwarding_note_handler
|
|
||||||
* - send to P2C the child pid
|
|
||||||
* - start forwarding notes to the father
|
|
||||||
*/
|
*/
|
||||||
switch(child = fork()){
|
*__libposix_pid = getpid();
|
||||||
|
open_sighelper_nanny();
|
||||||
|
switch(child = rfork(RFPROC|RFFDG)){
|
||||||
case -1:
|
case -1:
|
||||||
while(CHILD_READY(-2) == -1)
|
rend = *__libposix_pid;
|
||||||
;
|
while(rendezvous((void*)rend, "e") == (void*)-1)
|
||||||
|
sleep(100);
|
||||||
|
rfork(RFNOWAIT);
|
||||||
exits("rfork (child)");
|
exits("rfork (child)");
|
||||||
case 0:
|
case 0:
|
||||||
/* Beloved child here
|
/* Beloved child here
|
||||||
*/
|
*/
|
||||||
__libposix_setup_new_process();
|
__libposix_setup_new_process();
|
||||||
|
rend = *__libposix_pid;
|
||||||
|
while(rendezvous((void*)rend, "d") == (void*)-1)
|
||||||
|
sleep(100);
|
||||||
|
rfork(RFREND);
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
release_inherited_resources();
|
rend = child;
|
||||||
*__libposix_sigchld_target_pid = father;
|
while((buf = rendezvous((void*)rend, "")) == (void*)-1)
|
||||||
notify(forwarding_note_handler);
|
sleep(100);
|
||||||
snprint(proxy_name, sizeof(proxy_name), "libposix signal proxy %d < %d", father, child);
|
rend = *__libposix_pid;
|
||||||
while(CHILD_READY(child) == -1)
|
while(rendezvous((void*)rend, "d") == (void*)-1)
|
||||||
;
|
sleep(100);
|
||||||
forward_wait_msg(father, proxy_name);
|
|
||||||
|
/* 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:
|
default:
|
||||||
while((child = CHILD_READY(-3)) == -1)
|
rend = proxy;
|
||||||
;
|
while((buf = rendezvous((void*)rend, "")) == (void*)-1)
|
||||||
child = ~child;
|
sleep(100);
|
||||||
if(child < 0){
|
if(buf[0] == 'e')
|
||||||
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);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
while((c2p = C2P_READY(-3)) == -1)
|
|
||||||
;
|
|
||||||
c2p = ~c2p;
|
|
||||||
if(c2p < 0){
|
|
||||||
waitpid();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no need to lock: the child list is private */
|
/* no need to lock: the child list is private */
|
||||||
c = malloc(sizeof(ChildList));
|
c = malloc(sizeof(ChildList));
|
||||||
c->pid = p2c;
|
c->pid = proxy;
|
||||||
c->next = *__libposix_child_list;
|
c->next = *__libposix_child_list;
|
||||||
*__libposix_child_list = c;
|
*__libposix_child_list = c;
|
||||||
|
|
||||||
return p2c;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -19,22 +19,25 @@
|
||||||
/* POSIX signals have weird semantics that are hard to emulate in a
|
/* POSIX signals have weird semantics that are hard to emulate in a
|
||||||
* sane system without giving up on its sanity.
|
* sane system without giving up on its sanity.
|
||||||
*
|
*
|
||||||
* We distinguish control signals (SIGKILL, SIGSTOP, SIGCONT,
|
* We distinguish control signals (SIGKILL, SIGSTOP, SIGTSTP, SIGCONT,
|
||||||
* SIGABRT, SIGIOT), SIGCHLD/SIGCLD, timers' wakeups
|
* SIGABRT, SIGTTIN, SIGTTOU, SIGIOT), SIGCHLD/SIGCLD, timers' wakeups
|
||||||
* (SIGALRM, SIGPROF, SIGVTALRM) and all the others.
|
* (SIGALRM, SIGPROF, SIGVTALRM) and all the others.
|
||||||
*
|
*
|
||||||
* TRASMISSION
|
* TRASMISSION
|
||||||
* -----------
|
* -----------
|
||||||
* Signal transmission depends on the relation between the sender
|
* Signal transmission is done though a file server mounted /dev/posix/,
|
||||||
* and the receiver:
|
* provided by sys/posixly. On startup and at each fork, processes
|
||||||
* 1) if sender and receiver have no relation the signal is translated
|
* create a file named /dev/posix/signal with ORDWR mode and perm
|
||||||
* to a note and sent to the receiver(s);
|
* equals to their pid. Writing and Reading such file they can
|
||||||
* 2) if sender == receiver the signal trampoline is directly invoked
|
* control signal dispatching, process groups and so on.
|
||||||
* for all signals except control ones and the default disposition occurs if
|
*
|
||||||
* the trampoline does not handle the signal
|
* When a signal is written to /dev/posix/signal, it is translated for
|
||||||
* 3) if sender is parent or child of receiver the transmision
|
* each receiver to a note, and written to the specific note file.
|
||||||
* differs from the default if libposix_emulate_SIGCHLD() has been
|
*
|
||||||
* called during library initialization
|
* If the receiver is a known process, the note is in the format
|
||||||
|
* posix: si_signo si_pid si_uid si_value si_code
|
||||||
|
* otherwise, if possible, it is translated to an idiomatic note
|
||||||
|
* (eg "interrupt" or "alarm").
|
||||||
*
|
*
|
||||||
* Since notes in Jehanne are not reentrant, signals translated to
|
* Since notes in Jehanne are not reentrant, signals translated to
|
||||||
* notes will be enqueued in kernel. A special machinery is implemented
|
* notes will be enqueued in kernel. A special machinery is implemented
|
||||||
|
@ -53,14 +56,15 @@
|
||||||
* ----------------
|
* ----------------
|
||||||
* Control messages are translated by the receiver to equivalent actions:
|
* Control messages are translated by the receiver to equivalent actions:
|
||||||
* - SIGKILL => write "kill" to the control file of the current process
|
* - SIGKILL => write "kill" to the control file of the current process
|
||||||
* - SIGSTOP => write "stop" to the control file of the current process
|
* - SIGSTOP, SIGTSTP, SIGTTOU, SIGTTIN
|
||||||
|
* => write "stop" to the control file of the current process
|
||||||
|
* (when the signal is not handled nor ignored)
|
||||||
* - SIGABRT/SIGIOT => invoke the registered signal handlers and abort
|
* - SIGABRT/SIGIOT => invoke the registered signal handlers and abort
|
||||||
* the current process
|
* the current process
|
||||||
* - SIGCONT => invoke the registered signal handlers via the signal
|
* - SIGCONT => invoke the registered signal handlers via the signal
|
||||||
* trampoline and continue; note that (since a stopped
|
* trampoline and continue; note that (since a stopped
|
||||||
* process cannot resume itself) the sender will write
|
* process cannot resume itself) sys/posixly will write
|
||||||
* "start" to the control file of the receiver before
|
* "start" to the control file of the receiver.
|
||||||
* sending the note (unless SIGCHLD emulation is enable).
|
|
||||||
*
|
*
|
||||||
* SIGCHLD/SIGCLD
|
* SIGCHLD/SIGCLD
|
||||||
* --------------
|
* --------------
|
||||||
|
@ -72,30 +76,26 @@
|
||||||
*
|
*
|
||||||
* Such emulation changes the way POSIX_fork and POSIX_kill works.
|
* Such emulation changes the way POSIX_fork and POSIX_kill works.
|
||||||
*
|
*
|
||||||
* Each fork() will spawn two additional processes that are designed
|
* Each fork() will spawn an additional process that share the memory
|
||||||
* to proxy signals between the parent and the desired child:
|
* of the parent, and waits for the child, so that it can send SIGCHLD:
|
||||||
*
|
*
|
||||||
* parent
|
* parent
|
||||||
* +- proxy from parent to child (P2C)
|
* +- nanny
|
||||||
* +- proxy from child to parent (C2P)
|
|
||||||
* +- child
|
* +- child
|
||||||
*
|
*
|
||||||
* Fork will return the pid of P2C to the parent, so that the
|
* Such "nannies" connect to sys/posixly by creating /dev/posix/nanny
|
||||||
* parent process will see the first proxy as its child; the child will
|
* so that the filesystem will handle them differently:
|
||||||
* see the second as its parent. Each proxy waits for its child and
|
* - any signal for the nanny sent from the parent is delivered to the child
|
||||||
* forwards the notes it receive to its designed target.
|
* - 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
|
||||||
|
*
|
||||||
* Finally fork in child will return 0.
|
* Finally fork in child will return 0.
|
||||||
*
|
*
|
||||||
* When the child exits, C2P will send a SIGCHLD note to parent and
|
* When the child exits, the proxy will send a SIGCHLD sigchld to parent
|
||||||
* then exit with the same status. Then P2C will exit with
|
* and then exit with the same status.
|
||||||
* the same status too.
|
|
||||||
*
|
*
|
||||||
* As the parent process will see P2C as its child, it will send any
|
* As the parent process will see the proxy as its child, it will send
|
||||||
* signal to it via kill and will wait it on SIGCHLD.
|
* any signal to it via kill or sigqueue and will wait it on SIGCHLD.
|
||||||
* However, when this machinary is enabled, kill will treat all signals
|
|
||||||
* for forked children in the same way, sending them to P2C.
|
|
||||||
* It's P2C's responsibility to translate control messages as required,
|
|
||||||
* so that SIGCONT will work as expected.
|
|
||||||
*
|
*
|
||||||
* TIMERS
|
* TIMERS
|
||||||
* ------
|
* ------
|
||||||
|
@ -104,6 +104,7 @@
|
||||||
* expire in a signal handler (interrupting a blocking syscall) but
|
* expire in a signal handler (interrupting a blocking syscall) but
|
||||||
* without giving up the simplicity of notes.
|
* without giving up the simplicity of notes.
|
||||||
*
|
*
|
||||||
|
* (TO BE IMPLEMENTED: )
|
||||||
* We allocate these timers on libposix initialization. When normal
|
* We allocate these timers on libposix initialization. When normal
|
||||||
* code is running timers will be implemented via Jehanne's alarms,
|
* code is running timers will be implemented via Jehanne's alarms,
|
||||||
* producing a note on expiration that will be mapped to the proper
|
* producing a note on expiration that will be mapped to the proper
|
||||||
|
@ -122,16 +123,22 @@
|
||||||
#include <posix.h>
|
#include <posix.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
unsigned char *__signals_to_code_map;
|
|
||||||
unsigned char *__code_to_signal_map;
|
|
||||||
int *__handling_external_signal;
|
int *__handling_external_signal;
|
||||||
int *__restart_syscall;
|
int *__restart_syscall;
|
||||||
|
extern PosixSignalMask *__libposix_signal_mask;
|
||||||
|
extern int *__libposix_devsignal;
|
||||||
|
|
||||||
static int __sigrtmin;
|
typedef union {
|
||||||
static int __sigrtmax;
|
PosixSignalInfo signal;
|
||||||
int __min_known_sig;
|
char raw[sizeof(PosixSignalInfo)];
|
||||||
int __max_known_sig;
|
} SignalBuf;
|
||||||
static PosixSignalTrampoline __libposix_signal_trampoline;
|
typedef union {
|
||||||
|
PosixSignalMask signals;
|
||||||
|
char raw[sizeof(PosixSignalMask)];
|
||||||
|
} SigSetBuf;
|
||||||
|
|
||||||
|
static SignalConf signal_configurations[PosixNumberOfSignals];
|
||||||
|
SignalConf *__libposix_signals = signal_configurations;
|
||||||
|
|
||||||
typedef enum PosixSignalDisposition
|
typedef enum PosixSignalDisposition
|
||||||
{
|
{
|
||||||
|
@ -143,23 +150,37 @@ typedef enum PosixSignalDisposition
|
||||||
} PosixSignalDisposition;
|
} PosixSignalDisposition;
|
||||||
|
|
||||||
static PosixError
|
static PosixError
|
||||||
note_all_writable_processes(int sig)
|
note_all_writable_processes(PosixSignalInfo* siginfo)
|
||||||
{
|
{
|
||||||
// TODO: loop over writable note files and post note.
|
// TODO: loop over writable note files and post note.
|
||||||
return PosixEPERM;
|
return PosixEPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
terminated_by_signal(int sig)
|
terminated_by_signal(int signo)
|
||||||
{
|
{
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
|
||||||
__libposix_free_wait_list();
|
__libposix_free_wait_list();
|
||||||
|
|
||||||
snprint(buf, sizeof(buf), __POSIX_EXIT_SIGNAL_PREFIX "%d", sig);
|
snprint(buf, sizeof(buf), __POSIX_EXIT_SIGNAL_PREFIX "%d", signo);
|
||||||
exits(buf);
|
exits(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
__libposix_init_signal_handlers(void)
|
||||||
|
{
|
||||||
|
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(PosixSIGCHLD));
|
||||||
|
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(PosixSIGURG));
|
||||||
|
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(PosixSIGWINCH));
|
||||||
|
__libposix_signals[PosixSIGCHLD-1].handler = (void*)1;
|
||||||
|
__libposix_signals[PosixSIGCHLD-1].sa_restart = 1;
|
||||||
|
__libposix_signals[PosixSIGURG-1].handler = (void*)1;
|
||||||
|
__libposix_signals[PosixSIGURG-1].sa_restart = 1;
|
||||||
|
__libposix_signals[PosixSIGWINCH-1].handler = (void*)1;
|
||||||
|
__libposix_signals[PosixSIGWINCH-1].sa_restart = 1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
__libposix_send_control_msg(int pid, char *msg)
|
__libposix_send_control_msg(int pid, char *msg)
|
||||||
{
|
{
|
||||||
|
@ -189,7 +210,7 @@ ErrorBeforeOpen:
|
||||||
/* Executes a PosixSignalDisposition.
|
/* Executes a PosixSignalDisposition.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
execute_disposition(int sig, PosixSignalDisposition action)
|
execute_disposition(int signo, PosixSignalDisposition action)
|
||||||
{
|
{
|
||||||
int aborted_by_signal;
|
int aborted_by_signal;
|
||||||
|
|
||||||
|
@ -199,32 +220,27 @@ execute_disposition(int sig, PosixSignalDisposition action)
|
||||||
*__restart_syscall = 1;
|
*__restart_syscall = 1;
|
||||||
return 1;
|
return 1;
|
||||||
case TerminateTheProcess:
|
case TerminateTheProcess:
|
||||||
terminated_by_signal(sig);
|
terminated_by_signal(signo);
|
||||||
break;
|
break;
|
||||||
case TerminateTheProcessAndCoreDump:
|
case TerminateTheProcessAndCoreDump:
|
||||||
aborted_by_signal = 0;
|
aborted_by_signal = 0;
|
||||||
assert(aborted_by_signal);
|
assert(aborted_by_signal);
|
||||||
break;
|
break;
|
||||||
case StopTheProcess:
|
case StopTheProcess:
|
||||||
return __libposix_send_control_msg(getpid(), "stop");
|
return __libposix_send_control_msg(*__libposix_pid, "stop");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PosixSignalDisposition
|
static PosixSignalDisposition
|
||||||
default_signal_disposition(int code)
|
default_signal_disposition(PosixSignals signal)
|
||||||
{
|
{
|
||||||
PosixSignals signal;
|
if(signal >= PosixSIGRTMIN && signal <= PosixSIGRTMAX)
|
||||||
|
|
||||||
// see http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html
|
|
||||||
if(__sigrtmin != 0 && __sigrtmax != 0
|
|
||||||
&&(code >= __sigrtmin || code <= __sigrtmax))
|
|
||||||
return TerminateTheProcess;
|
return TerminateTheProcess;
|
||||||
|
|
||||||
signal = __code_to_signal_map[code];
|
|
||||||
switch(signal){
|
switch(signal){
|
||||||
default:
|
default:
|
||||||
sysfatal("libposix: undefined signal %d", code);
|
sysfatal("libposix: undefined signal %d", signal);
|
||||||
|
|
||||||
case PosixSIGALRM:
|
case PosixSIGALRM:
|
||||||
case PosixSIGHUP:
|
case PosixSIGHUP:
|
||||||
|
@ -255,7 +271,6 @@ default_signal_disposition(int code)
|
||||||
case PosixSIGXFSZ:
|
case PosixSIGXFSZ:
|
||||||
return TerminateTheProcessAndCoreDump;
|
return TerminateTheProcessAndCoreDump;
|
||||||
case PosixSIGCHLD:
|
case PosixSIGCHLD:
|
||||||
case PosixSIGCLD:
|
|
||||||
case PosixSIGURG:
|
case PosixSIGURG:
|
||||||
return IgnoreWithNoEffect;
|
return IgnoreWithNoEffect;
|
||||||
case PosixSIGCONT:
|
case PosixSIGCONT:
|
||||||
|
@ -263,209 +278,360 @@ default_signal_disposition(int code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PosixError
|
/* returns 1 if the signal handling has been completed, 0 otherwise */
|
||||||
__libposix_receive_signal(int sig)
|
int
|
||||||
|
__libposix_run_signal_handler(SignalConf *c, PosixSignalInfo *siginfo)
|
||||||
{
|
{
|
||||||
PosixSignalAction action = SignalDefault;
|
PosixSigHandler h;
|
||||||
PosixSignals psig = __code_to_signal_map[sig];
|
PosixSigAction a;
|
||||||
PosixSignalDisposition disposition;
|
PosixSignalMask m;
|
||||||
|
|
||||||
if(psig != PosixSIGKILL && psig != PosixSIGSTOP)
|
switch((uintptr_t)c->handler){
|
||||||
action = __libposix_signal_trampoline(sig);
|
case 0:
|
||||||
if(psig == PosixSIGABRT)
|
/* SIG_DFL */
|
||||||
action = SignalDefault; // lets abort despite the user will
|
if(c->sa_restart)
|
||||||
|
|
||||||
switch(action){
|
|
||||||
case SignalCatched:
|
|
||||||
break;
|
|
||||||
case SignalIgnored:
|
|
||||||
*__restart_syscall = 1;
|
*__restart_syscall = 1;
|
||||||
break;
|
break;
|
||||||
case SignalDefault:
|
case 1:
|
||||||
disposition = default_signal_disposition(sig);
|
/* SIG_IGN */
|
||||||
if(!execute_disposition(sig, disposition))
|
if(siginfo->si_signo == PosixSIGABRT)
|
||||||
return PosixEPERM;
|
|
||||||
break;
|
break;
|
||||||
case SignalError:
|
*__restart_syscall = 1;
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PosixError
|
PosixError
|
||||||
__libposix_notify_signal_to_process(int pid, int signal)
|
__libposix_receive_signal(PosixSignalInfo *siginfo)
|
||||||
{
|
{
|
||||||
char buf[128];
|
SignalConf *c;
|
||||||
int fd, n;
|
PosixSignalDisposition disposition;
|
||||||
|
PosixSignals signo = siginfo->si_signo;
|
||||||
|
|
||||||
snprint(buf, sizeof(buf), "/proc/%d/note", pid);
|
if(signo == PosixSIGKILL || signo == PosixSIGSTOP)
|
||||||
if((fd = open(buf, OWRITE)) < 0){
|
goto ExecuteDefaultDisposition;
|
||||||
if(access(buf, AEXIST) == 0)
|
|
||||||
|
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 PosixEPERM;
|
||||||
else
|
|
||||||
return PosixESRCH;
|
|
||||||
}
|
|
||||||
n = snprint(buf, sizeof(buf), __POSIX_SIGNAL_PREFIX "%d", signal);
|
|
||||||
write(fd, buf, n);
|
|
||||||
close(fd);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PosixError
|
long
|
||||||
notify_signal_to_group(int pid, int signal)
|
__libposix_sighelper_signal(PosixHelperCommand command, int posix_process_pid, PosixSignalInfo *siginfo)
|
||||||
{
|
{
|
||||||
char buf[128];
|
union {
|
||||||
int fd, n;
|
PosixHelperRequest request;
|
||||||
|
long raw;
|
||||||
|
} offset;
|
||||||
|
char buf[sizeof(PosixSignalInfo)];
|
||||||
|
|
||||||
snprint(buf, sizeof(buf), "/proc/%d/notepg", pid);
|
offset.request.command = command;
|
||||||
if((fd = open(buf, OWRITE)) < 0){
|
offset.request.target = posix_process_pid;
|
||||||
if(access(buf, AEXIST) == 0)
|
|
||||||
return PosixEPERM;
|
memcpy(buf, siginfo, sizeof(buf));
|
||||||
else
|
|
||||||
return PosixESRCH;
|
return pwrite(*__libposix_devsignal, buf, sizeof(buf), offset.raw);
|
||||||
}
|
}
|
||||||
n = snprint(buf, sizeof(buf), __POSIX_SIGNAL_PREFIX "%d", signal);
|
|
||||||
write(fd, buf, n);
|
long
|
||||||
close(fd);
|
__libposix_sighelper_set(PosixHelperCommand command, PosixSignalMask signal_set)
|
||||||
return 0;
|
{
|
||||||
|
union {
|
||||||
|
PosixHelperRequest request;
|
||||||
|
long raw;
|
||||||
|
} offset;
|
||||||
|
union {
|
||||||
|
PosixSignalMask mask;
|
||||||
|
char raw[sizeof(PosixSignalMask)];
|
||||||
|
} buffer;
|
||||||
|
|
||||||
|
offset.request.command = command;
|
||||||
|
offset.request.target = 0;
|
||||||
|
|
||||||
|
buffer.mask = signal_set;
|
||||||
|
|
||||||
|
return pwrite(*__libposix_devsignal, buffer.raw, sizeof(buffer.raw), offset.raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
PosixError
|
||||||
|
__libposix_notify_signal_to_process(int pid, PosixSignalInfo *siginfo)
|
||||||
|
{
|
||||||
|
long e = __libposix_sighelper_signal(PHSignalProcess, pid, siginfo);
|
||||||
|
return (PosixError)e;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PosixError
|
static PosixError
|
||||||
dispatch_signal(int pid, int sig)
|
notify_signal_to_group(int pid, PosixSignalInfo* siginfo)
|
||||||
|
{
|
||||||
|
long e = __libposix_sighelper_signal(PHSignalGroup, pid, siginfo);
|
||||||
|
return (PosixError)e;
|
||||||
|
}
|
||||||
|
|
||||||
|
PosixError
|
||||||
|
__libposix_dispatch_signal(int pid, PosixSignalInfo* siginfo)
|
||||||
{
|
{
|
||||||
PosixSignals signal;
|
|
||||||
PosixError error;
|
PosixError error;
|
||||||
switch(pid){
|
switch(pid){
|
||||||
case 0:
|
case 0:
|
||||||
return notify_signal_to_group(getpid(), sig);
|
return notify_signal_to_group(*__libposix_pid, siginfo);
|
||||||
case -1:
|
case -1:
|
||||||
return note_all_writable_processes(sig);
|
return note_all_writable_processes(siginfo);
|
||||||
default:
|
default:
|
||||||
if(pid < 0)
|
if(pid < 0)
|
||||||
return notify_signal_to_group(-pid, sig);
|
return notify_signal_to_group(-pid, siginfo);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
signal = __code_to_signal_map[sig];
|
error = __libposix_notify_signal_to_process(pid, siginfo);
|
||||||
error = __libposix_notify_signal_to_process(pid, sig);
|
if(siginfo->si_signo == PosixSIGCONT && !__libposix_is_child(pid))
|
||||||
if(signal == PosixSIGCONT && !__libposix_is_child(pid))
|
|
||||||
__libposix_send_control_msg(pid, "start");
|
__libposix_send_control_msg(pid, "start");
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
POSIX_kill(int *errnop, int pid, int sig)
|
translate_jehanne_kernel_note(const char *note, PosixSignalInfo *siginfo)
|
||||||
{
|
{
|
||||||
PosixSignals signal;
|
char *trap[3];
|
||||||
PosixError perror;
|
char *tmp;
|
||||||
|
|
||||||
signal = __code_to_signal_map[sig];
|
assert(siginfo->si_signo == 0);
|
||||||
if(signal == 0
|
|
||||||
&&(__sigrtmin != 0 && __sigrtmax != 0)
|
if(strncmp("trap: fault ", note, 12) == 0){
|
||||||
&&(sig < __sigrtmin || sig > __sigrtmax))
|
// trap: fault read addr=0x0 pc=0x400269
|
||||||
sysfatal("libposix: undefined signal %d", sig);
|
note += 12;
|
||||||
if(pid == getpid())
|
siginfo->si_signo = PosixSIGTRAP;
|
||||||
perror = __libposix_receive_signal(sig);
|
tmp = strdup(note);
|
||||||
|
if(getfields(tmp, trap, 3, 1, " ") == 3){
|
||||||
|
if(trap[0][0] == 'r')
|
||||||
|
siginfo->si_code = PosixSIFaultMapError;
|
||||||
else
|
else
|
||||||
perror = dispatch_signal(pid, sig);
|
siginfo->si_code = PosixSIFaultAccessError;
|
||||||
if(perror != 0){
|
siginfo->si_value._sival_raw = atoll(trap[1]+5);
|
||||||
*errnop = __libposix_get_errno(perror);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
return 0;
|
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);
|
||||||
|
}
|
||||||
|
// TODO: implement
|
||||||
|
|
||||||
|
return siginfo->si_signo == 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
translate_jehanne_note(char *note)
|
translate_jehanne_note(const char *note, PosixSignalInfo *siginfo)
|
||||||
{
|
{
|
||||||
// TODO: implement
|
if(note == nil || note[0] == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(strncmp("alarm", note, 5) == 0){
|
||||||
|
siginfo->si_signo = PosixSIGALRM;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(strncmp("sys: ", note, 5) == 0)
|
||||||
|
return translate_jehanne_kernel_note(note + 5, siginfo);
|
||||||
|
if(strncmp("interrupt", note, 9) == 0){
|
||||||
|
siginfo->si_signo = PosixSIGINT;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(strncmp("hangup", note, 6) == 0){
|
||||||
|
siginfo->si_signo = PosixSIGHUP;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
__libposix_note_to_signal(char *note)
|
__libposix_signal_to_note(const PosixSignalInfo *si, char *buf, int size)
|
||||||
{
|
{
|
||||||
return atoi(note+__POSIX_SIGNAL_PREFIX_LEN);
|
return
|
||||||
|
snprint(buf, size, __POSIX_SIGNAL_PREFIX "%d %d %d %#p %d",
|
||||||
|
si->si_signo, si->si_pid, si->si_uid,
|
||||||
|
si->si_value._sival_raw, si->si_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The format of a note sent by libposix as a signal is
|
||||||
|
*
|
||||||
|
* "posix: %d %d %d %#p %d", signo, pid, uid, value, code
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
__libposix_note_to_signal(const char *note, PosixSignalInfo *siginfo)
|
||||||
|
{
|
||||||
|
assert(siginfo->si_signo == 0); /* siginfo must be zeroed */
|
||||||
|
if(strncmp(note, __POSIX_SIGNAL_PREFIX, __POSIX_SIGNAL_PREFIX_LEN) != 0)
|
||||||
|
return translate_jehanne_note(note, siginfo);
|
||||||
|
char *rest = (char*)note + __POSIX_SIGNAL_PREFIX_LEN;
|
||||||
|
if(*rest == 0)
|
||||||
|
return 0;
|
||||||
|
siginfo->si_signo = strtol(rest, &rest, 0);
|
||||||
|
if(*rest == 0)
|
||||||
|
return 1;
|
||||||
|
siginfo->si_pid = strtol(rest, &rest, 0);
|
||||||
|
if(*rest == 0)
|
||||||
|
return 1;
|
||||||
|
siginfo->si_uid = strtoul(rest, &rest, 0);
|
||||||
|
if(*rest == 0)
|
||||||
|
return 1;
|
||||||
|
siginfo->si_value._sival_raw = strtoull(rest, &rest, 0);
|
||||||
|
if(*rest == 0)
|
||||||
|
return 1;
|
||||||
|
siginfo->si_code = strtoul(rest, &rest, 0);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
__libposix_note_handler(void *ureg, char *note)
|
__libposix_note_handler(void *ureg, char *note)
|
||||||
{
|
{
|
||||||
int sig;
|
PosixSignalInfo siginfo;
|
||||||
PosixError error;
|
PosixError error;
|
||||||
if(strncmp(note, __POSIX_SIGNAL_PREFIX, __POSIX_SIGNAL_PREFIX_LEN) != 0)
|
|
||||||
return translate_jehanne_note(note); // TODO: should we translate common notes?
|
memset(&siginfo, 0, sizeof(PosixSignalInfo));
|
||||||
sig = __libposix_note_to_signal(note);
|
|
||||||
if(sig < __min_known_sig || sig > __max_known_sig)
|
if(!__libposix_note_to_signal(note, &siginfo)
|
||||||
|
&& (siginfo.si_signo < 1 || siginfo.si_signo > PosixNumberOfSignals))
|
||||||
sysfatal("libposix: '%s' does not carry a signal", note);
|
sysfatal("libposix: '%s' does not carry a signal", note);
|
||||||
*__handling_external_signal = 1;
|
*__handling_external_signal = 1;
|
||||||
error = __libposix_receive_signal(sig);
|
error = __libposix_receive_signal(&siginfo);
|
||||||
*__handling_external_signal = 0;
|
*__handling_external_signal = 0;
|
||||||
|
werrstr("interrupted");
|
||||||
return error == 0;
|
return error == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
libposix_define_realtime_signals(int sigrtmin, int sigrtmax)
|
|
||||||
{
|
|
||||||
if(sigrtmin >= 256 || sigrtmin <=0)
|
|
||||||
sysfatal("libposix: invalid SIGRTMIN %d (must be positive and less then 256)", sigrtmin);
|
|
||||||
if(sigrtmax >= 256 || sigrtmax <=0)
|
|
||||||
sysfatal("libposix: invalid SIGRTMAX %d (must be positive and less then 256)", sigrtmax);
|
|
||||||
if(sigrtmax <= sigrtmin)
|
|
||||||
sysfatal("libposix: invalid SIGRTMAX %d (must be greater than SIGRTMIN %d)", sigrtmax, sigrtmin);
|
|
||||||
if(__libposix_initialized())
|
|
||||||
return 0;
|
|
||||||
__sigrtmin = sigrtmin;
|
|
||||||
__sigrtmax = sigrtmax;
|
|
||||||
if(sigrtmin < __min_known_sig || __min_known_sig == 0)
|
|
||||||
__min_known_sig = sigrtmin;
|
|
||||||
if(sigrtmax > __max_known_sig || __max_known_sig == 0)
|
|
||||||
__max_known_sig = sigrtmax;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
libposix_define_signal(PosixSignals signal, int code)
|
|
||||||
{
|
|
||||||
if(signal >= PosixNumberOfSignals)
|
|
||||||
sysfatal("libposix: unknown PosixSignal %d", signal);
|
|
||||||
if(code >= 256 || code <=0)
|
|
||||||
sysfatal("libposix: invalid signal number %d (must be positive and less then 256)", code);
|
|
||||||
if(__libposix_initialized())
|
|
||||||
return 0;
|
|
||||||
__signals_to_code_map[signal] = (unsigned char)code;
|
|
||||||
if(signal != PosixSIGCLD || code != __signals_to_code_map[PosixSIGCHLD]){
|
|
||||||
/* if SIGCHLD == SIGCLD then we use PosixSIGCHLD to identify the signal */
|
|
||||||
__code_to_signal_map[code] = (unsigned char)signal;
|
|
||||||
}
|
|
||||||
if(code < __min_known_sig || __min_known_sig == 0)
|
|
||||||
__min_known_sig = code;
|
|
||||||
if(code > __max_known_sig || __max_known_sig == 0)
|
|
||||||
__max_known_sig = code;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
libposix_set_signal_trampoline(PosixSignalTrampoline trampoline)
|
|
||||||
{
|
|
||||||
if(__libposix_initialized())
|
|
||||||
return 0;
|
|
||||||
if(trampoline == nil)
|
|
||||||
return 0;
|
|
||||||
__libposix_signal_trampoline = trampoline;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
__libposix_restart_syscall(void)
|
__libposix_restart_syscall(void)
|
||||||
{
|
{
|
||||||
int r = *__restart_syscall;
|
int r;
|
||||||
|
|
||||||
|
if(*__handling_external_signal)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = *__restart_syscall;
|
||||||
*__restart_syscall = 0;
|
*__restart_syscall = 0;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
__libposix_signal_check_conf(void)
|
POSIX_sigaction(int *errnop, int signo, const struct sigaction *act, struct sigaction *old)
|
||||||
{
|
{
|
||||||
if(__libposix_signal_trampoline == nil)
|
SignalConf *c, oconf;
|
||||||
sysfatal("libposix: no signal trampoline");
|
|
||||||
|
if(signo < 1 || signo > PosixNumberOfSignals)
|
||||||
|
goto FailWithEINVAL;
|
||||||
|
|
||||||
|
c = __libposix_signals + (signo-1);
|
||||||
|
|
||||||
|
if(old)
|
||||||
|
memcpy(&oconf, c, sizeof(SignalConf));
|
||||||
|
|
||||||
|
if(act){
|
||||||
|
memset(c, 0, sizeof(SignalConf));
|
||||||
|
if(signo == PosixSIGKILL || signo == PosixSIGSTOP)
|
||||||
|
goto FailWithEINVAL;
|
||||||
|
if(act->sa_flags & PosixSAFSigInfo){
|
||||||
|
c->sa_siginfo = 1;
|
||||||
|
c->handler = act->sa_sigaction;
|
||||||
|
} else {
|
||||||
|
c->handler = act->sa_handler;
|
||||||
|
}
|
||||||
|
c->mask = act->sa_mask & ~((255UL<<56) | SIGNAL_MASK(PosixSIGKILL) | SIGNAL_MASK(PosixSIGSTOP));
|
||||||
|
if(act->sa_flags & PosixSAFResetHandler)
|
||||||
|
c->sa_resethand = 1;
|
||||||
|
else
|
||||||
|
c->sa_resethand = 0;
|
||||||
|
if(act->sa_flags & PosixSAFRestart)
|
||||||
|
c->sa_restart = 1;
|
||||||
|
else
|
||||||
|
c->sa_restart = 0;
|
||||||
|
if(signo == PosixSIGCHLD){
|
||||||
|
if(act->sa_flags & PosixSAFNoChildrenWait)
|
||||||
|
c->sa_nochildwait = 1;
|
||||||
|
else
|
||||||
|
c->sa_nochildwait = 0;
|
||||||
|
if(c->handler == (void*)1) /* SIGCHLD && SIG_IGN => SA_NOCLDWAIT */
|
||||||
|
c->sa_nochildwait = 1;
|
||||||
|
}
|
||||||
|
if(c->handler == (void*)1){
|
||||||
|
/* ignore signal */
|
||||||
|
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(signo));
|
||||||
|
} else if(c->handler == (void*)0){
|
||||||
|
/* default behavior */
|
||||||
|
switch(signo){
|
||||||
|
case PosixSIGCHLD:
|
||||||
|
case PosixSIGURG:
|
||||||
|
case PosixSIGWINCH:
|
||||||
|
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(signo));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
__libposix_sighelper_set(PHEnableSignal, SIGNAL_MASK(signo));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* do not ignore signal */
|
||||||
|
__libposix_sighelper_set(PHEnableSignal, SIGNAL_MASK(signo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(old){
|
||||||
|
if(oconf.sa_siginfo){
|
||||||
|
old->sa_sigaction = oconf.handler;
|
||||||
|
old->sa_mask = oconf.mask;
|
||||||
|
old->sa_flags = 0;
|
||||||
|
if(oconf.sa_siginfo)
|
||||||
|
old->sa_flags |= PosixSAFSigInfo;
|
||||||
|
if(oconf.sa_resethand)
|
||||||
|
old->sa_flags |= PosixSAFResetHandler;
|
||||||
|
if(oconf.sa_restart)
|
||||||
|
old->sa_flags |= PosixSAFRestart;
|
||||||
|
if(oconf.sa_nochildwait)
|
||||||
|
old->sa_flags |= PosixSAFNoChildrenWait;
|
||||||
|
} else {
|
||||||
|
old->sa_handler = oconf.handler;
|
||||||
|
old->sa_flags = 0;
|
||||||
|
old->sa_mask = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
FailWithEINVAL:
|
||||||
|
*errnop = __libposix_get_errno(PosixEINVAL);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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 PosixTimevalReader __libposix_timeval_reader;
|
||||||
static PosixTimezoneReader __libposix_timezone_reader;
|
static PosixTimezoneReader __libposix_timezone_reader;
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
POSIX_alarm(int *errnop, unsigned int seconds)
|
||||||
|
{
|
||||||
|
long r = alarm(seconds * 1000);
|
||||||
|
return r/1000;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
POSIX_gettimeofday(int *errnop, void *timeval, void *timezone)
|
POSIX_gettimeofday(int *errnop, void *timeval, void *timezone)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue