use alt signal stack when present for implementation-internal signals
[musl] / src / misc / forkpty.c
index 0bbf2de..caf13ad 100644 (file)
@@ -1,25 +1,57 @@
 #include <pty.h>
+#include <utmp.h>
 #include <unistd.h>
-#include <sys/ioctl.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <pthread.h>
 
-int forkpty(int *m, char *name, const struct termios *tio, const struct winsize *ws)
+int forkpty(int *pm, char *name, const struct termios *tio, const struct winsize *ws)
 {
-       int s;
-       pid_t pid;
+       int m, s, ec=0, p[2], cs;
+       pid_t pid=-1;
+       sigset_t set, oldset;
+
+       if (openpty(&m, &s, name, tio, ws) < 0) return -1;
+
+       sigfillset(&set);
+       pthread_sigmask(SIG_BLOCK, &set, &oldset);
+       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+
+       if (pipe2(p, O_CLOEXEC)) {
+               close(s);
+               goto out;
+       }
 
-       if (openpty(m, &s, name, tio, ws) < 0) return -1;
        pid = fork();
        if (!pid) {
-               close(*m);
-               setsid();
-               ioctl(s, TIOCSCTTY, (char *)0);
-               dup2(s, 0);
-               dup2(s, 1);
-               dup2(s, 2);
-               if (s>2) close(s);
+               close(m);
+               close(p[0]);
+               if (login_tty(s)) {
+                       write(p[1], &errno, sizeof errno);
+                       _exit(127);
+               }
+               close(p[1]);
+               pthread_setcancelstate(cs, 0);
+               pthread_sigmask(SIG_SETMASK, &oldset, 0);
                return 0;
        }
        close(s);
-       if (pid < 0) close(*m);
+       close(p[1]);
+       if (read(p[0], &ec, sizeof ec) > 0) {
+               int status;
+               waitpid(pid, &status, 0);
+               pid = -1;
+               errno = ec;
+       }
+       close(p[0]);
+
+out:
+       if (pid > 0) *pm = m;
+       else close(m);
+
+       pthread_setcancelstate(cs, 0);
+       pthread_sigmask(SIG_SETMASK, &oldset, 0);
+
        return pid;
 }