pid_t pty_fork(int *ptrfdm, char** pts_name) { pid_t pid; char* name; int master_fd, pty_fd; if ((master_fd = ptm_open()) < 0) { err_sys("ERROR: ptm_open() failed [%d]\n", master_fd); } if ((name = ptsname(master_fd)) == NULL) { close(master_fd); return -1; } // Put values to the output params *pts_name = name; *ptrfdm = master_fd; if ((pid = fork()) < 0) { printf("FAILED"); return (-1); } if (pid == 0) { /* child */ if (setsid() < 0) { err_sys("setsid error"); } if ((pty_fd = pts_open(master_fd)) < 0) { err_sys("can't open slave pty"); } close(master_fd); dup_fd(pty_fd); return (0); /* child returns 0 just like fork() */ } else { /* parent */ return (pid); /* parent returns pid of child */ } }
int connect_daemon(int argc, char *argv[], int ppid) { int uid = getuid(); int ptmx = -1; char pts_slave[PATH_MAX]; struct sockaddr_un sun; // Open a socket to the daemon int socketfd = socket(AF_LOCAL, SOCK_STREAM, 0); if (socketfd < 0) { PLOGE("socket"); exit(-1); } if (fcntl(socketfd, F_SETFD, FD_CLOEXEC)) { PLOGE("fcntl FD_CLOEXEC"); exit(-1); } memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_LOCAL; sprintf(sun.sun_path, "%s/server", REQUESTOR_DAEMON_PATH); memset(sun.sun_path, 0, sizeof(sun.sun_path)); memcpy(sun.sun_path, "\0" "SUPERUSER", strlen("SUPERUSER") + 1); if (0 != connect(socketfd, (struct sockaddr*)&sun, sizeof(sun))) { PLOGE("connect"); exit(-1); } LOGD("connecting client %d", getpid()); int mount_storage = getenv("MOUNT_EMULATED_STORAGE") != NULL; // Determine which one of our streams are attached to a TTY int atty = 0; // Send TTYs directly (instead of proxying with a PTY) if // the SUPERUSER_SEND_TTY environment variable is set. if (getenv("SUPERUSER_SEND_TTY") == NULL) { if (isatty(STDIN_FILENO)) atty |= ATTY_IN; if (isatty(STDOUT_FILENO)) atty |= ATTY_OUT; if (isatty(STDERR_FILENO)) atty |= ATTY_ERR; } if (atty) { // We need a PTY. Get one. ptmx = pts_open(pts_slave, sizeof(pts_slave)); if (ptmx < 0) { PLOGE("pts_open"); exit(-1); } } else { pts_slave[0] = '\0'; } // Send some info to the daemon, starting with our PID write_int(socketfd, getpid()); // Send the slave path to the daemon // (This is "" if we're not using PTYs) write_string(socketfd, pts_slave); // User ID write_int(socketfd, uid); // Parent PID write_int(socketfd, ppid); write_int(socketfd, mount_storage); // Send stdin if (atty & ATTY_IN) { // Using PTY send_fd(socketfd, -1); } else { send_fd(socketfd, STDIN_FILENO); } // Send stdout if (atty & ATTY_OUT) { // Forward SIGWINCH watch_sigwinch_async(STDOUT_FILENO, ptmx); // Using PTY send_fd(socketfd, -1); } else { send_fd(socketfd, STDOUT_FILENO); } // Send stderr if (atty & ATTY_ERR) { // Using PTY send_fd(socketfd, -1); } else { send_fd(socketfd, STDERR_FILENO); } // Number of command line arguments write_int(socketfd, mount_storage ? argc - 1 : argc); // Command line arguments int i; for (i = 0; i < argc; i++) { if (i == 1 && mount_storage) { continue; } write_string(socketfd, argv[i]); } // Wait for acknowledgement from daemon read_int(socketfd); if (atty & ATTY_IN) { setup_sighandlers(); pump_stdin_async(ptmx); } if (atty & ATTY_OUT) { pump_stdout_blocking(ptmx); } // Get the exit code int code = read_int(socketfd); close(socketfd); LOGD("client exited %d", code); return code; }