libposix: deep refactor; add sys/posixly command

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

2
cfg/mksh/profile Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

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

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

@ -21,70 +21,83 @@
#include <posix.h>
#include "internal.h"
typedef union {
int group;
char raw[sizeof(int)];
} IntBuf;
extern int *__libposix_devsignal;
int __libposix_session_leader = -1;
static int
get_noteid(int *errnop, int pid)
get_ppid(int pid)
{
int n, f;
char buf[30];
sprint(buf, "/proc/%d/noteid", pid);
f = open(buf, OREAD);
if(f < 0){
*errnop = __libposix_get_errno(PosixEPERM);
long n;
char buf[32];
sprint(buf, "/proc/%d/ppid", pid);
n = remove(buf);
if(n == -1)
return -1;
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
set_noteid(int *errnop, int pid, int noteid)
set_group_id(int *errnop, int pid, int group)
{
int n, f;
char buf[30];
int mypid, ppid;
if(pid == 0)
pid = getpid();
if(noteid == 0){
noteid = get_noteid(errnop, pid);
if(noteid < 0)
return noteid;
}
sprint(buf, "/proc/%d/noteid", pid);
f = open(buf, OWRITE);
if(f < 0) {
*errnop = __libposix_get_errno(PosixESRCH);
if(pid < 0 || group < 0){
*errnop = __libposix_get_errno(PosixEINVAL);
return -1;
}
n = sprint(buf, "%d", noteid);
n = write(f, buf, n);
if(n < 0){
if(pid == __libposix_session_leader){
*errnop = __libposix_get_errno(PosixEPERM);
return -1;
}
close(f);
return 0;
mypid = *__libposix_pid;
if(pid == 0 && group == 0){
/* the caller wants a new process group */
CreateNewProcessGroup:
rfork(RFNOTEG);
return __libposix_sighelper_cmd(PHSetProcessGroup, mypid);
}
ppid = get_ppid(pid);
if(ppid == -1 || pid != mypid && mypid != ppid){
*errnop = __libposix_get_errno(PosixESRCH);
return -1;
}
if(pid == group && pid == mypid)
goto CreateNewProcessGroup;
return __libposix_sighelper_set_pgid(pid, group);
}
int
POSIX_getuid(int *errnop)
{
return 0;
return 1000;
}
int
POSIX_geteuid(int *errnop)
{
return 0;
return 1000;
}
int
@ -102,7 +115,7 @@ POSIX_seteuid(int *errnop, int euid)
int
POSIX_setreuid(int *errnop, int ruid, int euid)
{
return 0;
return 1000;
}
int
@ -138,61 +151,129 @@ POSIX_setregid(int *errnop, int rgid, int egid)
int
POSIX_getpgrp(int *errnop)
{
int pid = getpid();
return get_noteid(errnop, pid);
long ret;
int pid = *__libposix_pid;
ret = __libposix_sighelper_cmd(PHGetProcessGroupId, pid);
if(ret < 0)
return pid;
return ret;
}
int
POSIX_getpgid(int *errnop, int pid)
{
return get_noteid(errnop, pid);
long ret;
ret = __libposix_sighelper_cmd(PHGetProcessGroupId, pid);
if(ret < 0)
*errnop = __libposix_get_errno(PosixESRCH);
return ret;
}
int
POSIX_setpgid(int *errnop, int pid, int pgid)
{
if(pid < 0 || pgid < 0){
*errnop = __libposix_get_errno(PosixEINVAL);
return -1;
}
return set_noteid(errnop, pid, pgid);
return set_group_id(errnop, pid, pgid);
}
int
POSIX_getsid(int *errnop, int pid)
{
int reqnoteid, mynoteid;
int mypid;
long sid;
char buf[32];
if(pid < 0){
FailWithESRCH:
*errnop = __libposix_get_errno(PosixESRCH);
return -1;
}
snprint(buf, sizeof(buf), "/proc/%d/ns", pid);
if(access(buf, AEXIST) != 0)
goto FailWithESRCH;
mypid = *__libposix_pid;
if(pid == 0)
pid = getpid();
else if(pid == getpid())
return __libposix_session_leader;
reqnoteid = get_noteid(errnop, pid);
if(reqnoteid < 0)
return reqnoteid;
if(__libposix_session_leader < 0)
return reqnoteid;
mynoteid = POSIX_getpgrp(errnop);
if(mynoteid == reqnoteid){
/* if it share our pgrp (aka noteid), it shares
* our session leader
*/
return __libposix_session_leader;
pid = mypid;
sid = __libposix_sighelper_cmd(PHGetSessionId, pid);
if(sid < 0){
*errnop = __libposix_get_errno(PosixEPERM);
return -1;
}
return reqnoteid;
if(pid == mypid)
__libposix_session_leader = (int)sid;
return sid;
}
int
POSIX_setsid(int *errnop)
{
if(rfork(RFNAMEG|RFNOTEG) < 0){
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);
return -1;
}
__libposix_session_leader = POSIX_getpgrp(errnop);
return __libposix_session_leader;
}

View File

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

View File

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

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

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

View File

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

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

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

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

View File

@ -0,0 +1,46 @@
/*
* This file is part of Jehanne.
*
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3 of the License.
*
* Jehanne is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
*/
#include <u.h>
#include <lib9.h>
#include <posix.h>
#include "internal.h"
int
POSIX_sigsuspend(int *errnop, const PosixSignalMask *mask)
{
PosixSignalMask old;
if(mask == nil){
*errnop = __libposix_get_errno(PosixEFAULT);
return -1;
}
if(POSIX_sigprocmask(errnop, PosixSPMSetMask, mask, &old) != 0)
return -1;
do
rendezvous((void*)~0, (void*)1);
while(__libposix_restart_syscall());
if(POSIX_sigprocmask(errnop, PosixSPMSetMask, &old, nil) != 0)
return -1;
*errnop = __libposix_get_errno(PosixEINTR);
return -1;
}

View File

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

View File

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