diff options
| author | Ned T. Crigler <crigler@users.sourceforge.net> | 2001-11-05 20:02:58 +0000 |
|---|---|---|
| committer | Ned T. Crigler <crigler@users.sourceforge.net> | 2001-11-05 20:02:58 +0000 |
| commit | 203193838dbc2e6acea953c484a030e5632ca5cf (patch) | |
| tree | 61099a8f5e50ceca2e1a15de33a4876c48b5a99b /master.c | |
| parent | ba4a3a502fd67967c35638c454badbf2a3933a36 (diff) | |
Portability updates thanks to sourceforge's compile farm. dtach should now
work on: FreeBSD, Debian/alpha, Debian/sparc, Debian/PPC, and Solaris.
Bump version.
Diffstat (limited to 'master.c')
| -rw-r--r-- | master.c | 261 |
1 files changed, 196 insertions, 65 deletions
@@ -18,58 +18,73 @@ */ #include "detach.h" -// The pty struct - The pty information is stored here. +/* The pty struct - The pty information is stored here. */ struct pty { - // File descriptor of the pty + /* File descriptor of the pty */ int fd; - // The terminal parameters of the pty. Old and new for comparision - // purposes. +#ifdef BROKEN_MASTER + /* File descriptor of the slave side of the pty. For broken systems. */ + int slave; +#endif + /* The terminal parameters of the pty. Old and new for comparision + ** purposes. */ struct termios term; - // The current window size of the pty. + /* The current window size of the pty. */ struct winsize ws; }; -// The poll structures +/* The poll structures */ static struct pollfd *polls; -// The number of active poll slots +/* The number of active poll slots */ static int num_polls; -// Boolean array for whether a particular connection is attached. +/* Boolean array for whether a particular connection is attached. */ static int *attached; -// The highest file descriptor possible, as returned by getrlimit. +/* The highest file descriptor possible, as returned by getrlimit. */ static int highest_fd; -// The number of fixed slots in the poll structures +/* The number of fixed slots in the poll structures */ #define FIXED_SLOTS 2 -// Unlink the socket +#ifndef HAVE_FORKPTY +pid_t forkpty(int *amaster, char *name, struct termios *termp, + struct winsize *winp); +#endif + +/* Unlink the socket */ static void unlink_socket(void) { unlink(sockname); } -// Signal +/* Signal */ static RETSIGTYPE die(int sig) { - // Well, the child died. + /* Well, the child died. */ if (sig == SIGCHLD) + { +#ifdef BROKEN_MASTER + /* Damn you Solaris! */ + close(polls[1].fd); +#endif return; + } exit(1); } -// Initialize the pty structure. +/* Initialize the pty structure. */ static int init_pty(struct pty *pty, char **argv) { pid_t pid; - // Use the original terminal's settings. We don't have to set the - // window size here, because the attacher will send it in a packet. + /* Use the original terminal's settings. We don't have to set the + ** window size here, because the attacher will send it in a packet. */ pty->term = orig_term; - // Create the pty process + /* Create the pty process */ pid = forkpty(&pty->fd, NULL, &pty->term, NULL); if (pid < 0) return -1; @@ -77,59 +92,74 @@ init_pty(struct pty *pty, char **argv) { int i; - // Child.. Close some file descriptors and execute the program. + /* Child.. Close some file descriptors and execute the + ** program. */ for (i = highest_fd; i > 2; --i) close(i); execvp(*argv, argv); exit(127); } - // Parent.. Finish up and return + /* Parent.. Finish up and return */ +#ifdef BROKEN_MASTER + { + char *buf; + + buf = ptsname(pty->fd); + pty->slave = open(buf, O_RDWR|O_NOCTTY); + } +#endif return 0; } -// Creates a new unix domain socket. +/* Creates a new unix domain socket. */ static int create_socket(char *name) { int s; - struct sockaddr_un sun; + struct sockaddr_un sockun; s = socket(PF_UNIX, SOCK_STREAM, 0); if (s < 0) return -1; - sun.sun_family = AF_UNIX; - strcpy(sun.sun_path, name); - if (bind(s, (struct sockaddr*)&sun, sizeof(sun)) < 0) + sockun.sun_family = AF_UNIX; + strcpy(sockun.sun_path, name); + if (bind(s, (struct sockaddr*)&sockun, sizeof(sockun)) < 0) return -1; if (listen(s, 128) < 0) return -1; - // chmod it to prevent any suprises + /* chmod it to prevent any suprises */ if (chmod(name, 0600) < 0) return -1; return s; } -// Process activity on a pty - Input and terminal changes are sent out to -// the attached clients. If the pty goes away, we die. +/* Process activity on a pty - Input and terminal changes are sent out to +** the attached clients. If the pty goes away, we die. */ static void pty_activity(struct pty *pty) { int i, len; unsigned char buf[BUFSIZE]; - // Read the pty activity + /* Read the pty activity */ len = read(pty->fd, buf, sizeof(buf)); - // Error -> die + /* Error -> die */ if (len <= 0) exit(1); - // Get the current terminal settings. +#ifdef BROKEN_MASTER + /* Get the current terminal settings. */ + if (tcgetattr(pty->slave, &pty->term) < 0) + exit(1); +#else + /* Get the current terminal settings. */ if (tcgetattr(pty->fd, &pty->term) < 0) exit(1); +#endif - // Send it out to the clients. + /* Send it out to the clients. */ for (i = FIXED_SLOTS; i < num_polls; ++i) { if (attached[polls[i].fd]) @@ -137,18 +167,18 @@ pty_activity(struct pty *pty) } } -// Process activity on the control socket +/* Process activity on the control socket */ static void control_activity(int s) { int fd; - // Accept the new client and link it in. + /* Accept the new client and link it in. */ fd = accept(s, 0, 0); if (fd < 0) return; - // Link it in. + /* Link it in. */ polls[num_polls].fd = fd; polls[num_polls].events = POLLIN; polls[num_polls].revents = 0; @@ -156,18 +186,18 @@ control_activity(int s) ++num_polls; } -// Process activity from a client. +/* Process activity from a client. */ static void client_activity(int i, struct pty *pty) { int len; struct packet pkt; - // Read the activity. + /* Read the activity. */ len = read(polls[i].fd, &pkt, sizeof(pkt)); if (len <= 0) { - // Close the socket and go bye bye + /* Close the socket and go bye bye */ attached[polls[i].fd]=0; close(polls[i].fd); memcpy(polls + i, polls + i + 1, num_polls - i); @@ -175,36 +205,36 @@ client_activity(int i, struct pty *pty) return; } - // Okay, check the command byte. Push out data if we need to. + /* Okay, check the command byte. Push out data if we need to. */ if (pkt.type == MSG_PUSH) write(pty->fd, pkt.u.buf, pkt.len); - // Window size change. + /* Window size change. */ else if (pkt.type == MSG_WINCH) { pty->ws = pkt.u.ws; ioctl(pty->fd, TIOCSWINSZ, &pty->ws); } - // Redraw request? + /* Redraw request? */ else if (pkt.type == MSG_REDRAW) { char c = '\f'; - // Guess that ^L might work under certain conditions. + /* Guess that ^L might work under certain conditions. */ if (((pty->term.c_lflag & (ECHO|ICANON)) == 0) && (pty->term.c_cc[VMIN] == 1)) { write(pty->fd, &c, sizeof(c)); } } - // Attach request? + /* Attach request? */ else if (pkt.type == MSG_ATTACH) attached[polls[i].fd] = 1; else if (pkt.type == MSG_DETACH) attached[polls[i].fd] = 0; } -// The master process - It watches over the pty process and the attached -// clients. +/* The master process - It watches over the pty process and the attached */ +/* clients. */ static void master_process(int s, char **argv) { @@ -214,8 +244,8 @@ master_process(int s, char **argv) #ifdef HAVE_GETRLIMIT struct rlimit rlim; - // Dynamically allocate structures based on the number of file - // descriptors. + /* Dynamically allocate structures based on the number of file + ** descriptors. */ if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { @@ -224,25 +254,25 @@ master_process(int s, char **argv) } highest_fd = rlim.rlim_cur; #else - // We can't query the OS for the number of file descriptors, so - // we pull a number out of the air. + /* We can't query the OS for the number of file descriptors, so + ** we pull a number out of the air. */ highest_fd = 1024; #endif polls = (struct pollfd*)malloc(highest_fd * sizeof(struct pollfd)); attached = (int*)malloc(highest_fd * sizeof(int)); - // Okay, disassociate ourselves from the original terminal, as we - // don't care what happens to it. + /* Okay, disassociate ourselves from the original terminal, as we + ** don't care what happens to it. */ setsid(); - // Create a pty in which the process is running. + /* Create a pty in which the process is running. */ if (init_pty(&pty, argv) < 0) { printf("%s: init_pty: %s\n", progname, strerror(errno)); exit(1); } - // Set up some signals. + /* Set up some signals. */ signal(SIGPIPE, SIG_IGN); signal(SIGXFSZ, SIG_IGN); signal(SIGHUP, SIG_IGN); @@ -252,16 +282,16 @@ master_process(int s, char **argv) signal(SIGTERM, die); signal(SIGCHLD, die); - // Close the original terminal. We are now a daemon. + /* Close the original terminal. We are now a daemon. */ fclose(stdin); fclose(stdout); fclose(stderr); - // Set a trap to unlink the socket when we die + /* Set a trap to unlink the socket when we die */ atexit(unlink_socket); - // Set up the poll structures. Slot 0 is the control socket, slot 1 - // is the pty, and slot 2 .. n is the connected clients. + /* Set up the poll structures. Slot 0 is the control socket, slot 1 + ** is the pty, and slot 2 .. n is the connected clients. */ polls[0].fd = s; polls[0].events = POLLIN; polls[0].revents = 0; @@ -270,23 +300,23 @@ master_process(int s, char **argv) polls[1].revents = 0; num_polls = FIXED_SLOTS; - // Loop forever. + /* Loop forever. */ while (1) { - // Wait for something to happen. + /* Wait for something to happen. */ if (poll(polls, num_polls, -1) < 0) { if (errno == EINTR || errno == EAGAIN) continue; exit(1); } - // pty activity? + /* pty activity? */ if (polls[1].revents != 0) pty_activity(&pty); - // New client? + /* New client? */ if (polls[0].revents != 0) control_activity(s); - // Activity on a client? + /* Activity on a client? */ for (i = 2; i < num_polls; ++i) { if (polls[i].revents != 0) @@ -301,7 +331,7 @@ master_main(char **argv) int s; pid_t pid; - // Create the unix domain socket. + /* Create the unix domain socket. */ s = create_socket(sockname); if (s < 0) { @@ -309,7 +339,7 @@ master_main(char **argv) return 1; } - // Fork off so we can daemonize and such + /* Fork off so we can daemonize and such */ pid = fork(); if (pid < 0) { @@ -318,10 +348,111 @@ master_main(char **argv) } else if (pid == 0) { - // Child - this becomes the master + /* Child - this becomes the master */ master_process(s, argv); return 0; } - // Parent - just return. + /* Parent - just return. */ return 0; } + +/* BSDish functions for systems that don't have them. */ +#ifndef HAVE_OPENPTY +#define HAVE_OPENPTY +/* openpty: Use /dev/ptmx and Unix98 if we have it. */ +#if defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT) +int +openpty(int *amaster, int *aslave, char *name, struct termios *termp, + struct winsize *winp) +{ + int master, slave; + char *buf; + + master = open("/dev/ptmx", O_RDWR); + if (master < 0) + return -1; + if (grantpt(master) < 0) + return -1; + if (unlockpt(master) < 0) + return -1; + buf = ptsname(master); + if (!buf) + return -1; + + slave = open(buf, O_RDWR|O_NOCTTY); + if (slave < 0) + return -1; + +#ifdef I_PUSH + if (ioctl(slave, I_PUSH, "ptem") < 0) + return -1; + if (ioctl(slave, I_PUSH, "ldterm") < 0) + return -1; +#endif + + *amaster = master; + *aslave = slave; + if (name) + strcpy(name, buf); + if (termp) + tcsetattr(slave, TCSAFLUSH, termp); + if (winp) + ioctl(slave, TIOCSWINSZ, winp); + return 0; +} +#else +#error Do not know how to define openpty. +#endif +#endif + +#ifndef HAVE_FORKPTY +#if defined(HAVE_OPENPTY) +pid_t +forkpty(int *amaster, char *name, struct termios *termp, + struct winsize *winp) +{ + pid_t pid; + int master, slave; + + if (openpty(&master, &slave, name, termp, winp) < 0) + return -1; + *amaster = master; + + /* Fork off... */ + pid = fork(); + if (pid < 0) + return -1; + else if (pid == 0) + { + char *buf; + int fd; + + setsid(); +#ifdef TIOCSCTTY + buf = NULL; + if (ioctl(slave, TIOCSCTTY, NULL) < 0) + _exit(1); +#else + buf = ptsname(master); + fd = open(buf, O_RDWR); + close(fd); +#endif + dup2(slave, 0); + dup2(slave, 1); + dup2(slave, 2); + + if (slave > 2) + close(slave); + close(master); + return 0; + } + else + { + close(slave); + return pid; + } +} +#else +#error Do not know how to define forkpty. +#endif +#endif |
