"Fossies" - the Fresh Open Source Software Archive

Member "reptyr-reptyr-0.8.0/reptyr.c" (29 Sep 2020, 8994 Bytes) of package /linux/privat/reptyr-reptyr-0.8.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "reptyr.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) 2011 by Nelson Elhage
    3  *
    4  * Permission is hereby granted, free of charge, to any person obtaining a copy
    5  * of this software and associated documentation files (the "Software"), to deal
    6  * in the Software without restriction, including without limitation the rights
    7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    8  * copies of the Software, and to permit persons to whom the Software is
    9  * furnished to do so, subject to the following conditions:
   10  *
   11  * The above copyright notice and this permission notice shall be included in
   12  * all copies or substantial portions of the Software.
   13  *
   14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   20  * THE SOFTWARE.
   21  */
   22 #include <fcntl.h>
   23 #include <unistd.h>
   24 #include <sys/types.h>
   25 #include <sys/select.h>
   26 #include <sys/ioctl.h>
   27 #include <stdio.h>
   28 #include <stdlib.h>
   29 #include <errno.h>
   30 #include <string.h>
   31 #include <stdarg.h>
   32 #include <termios.h>
   33 #include <signal.h>
   34 
   35 #include "reptyr.h"
   36 #include "reallocarray.h"
   37 #include "platform/platform.h"
   38 
   39 static int verbose = 0;
   40 
   41 void _debug(const char *pfx, const char *msg, va_list ap) {
   42 
   43     if (pfx)
   44         fprintf(stderr, "%s", pfx);
   45     vfprintf(stderr, msg, ap);
   46     fprintf(stderr, "\n");
   47 }
   48 
   49 void die(const char *msg, ...) {
   50     va_list ap;
   51     va_start(ap, msg);
   52     _debug("[!] ", msg, ap);
   53     va_end(ap);
   54 
   55     exit(1);
   56 }
   57 
   58 void debug(const char *msg, ...) {
   59 
   60     va_list ap;
   61 
   62     if (!verbose)
   63         return;
   64 
   65     va_start(ap, msg);
   66     _debug("[+] ", msg, ap);
   67     va_end(ap);
   68 }
   69 
   70 void error(const char *msg, ...) {
   71     va_list ap;
   72     va_start(ap, msg);
   73     _debug("[-] ", msg, ap);
   74     va_end(ap);
   75 }
   76 
   77 void setup_raw(struct termios *save) {
   78     struct termios set;
   79     if (tcgetattr(0, save) < 0) {
   80         fprintf(stderr, "Unable to read terminal attributes: %m");
   81         return;
   82     }
   83     set = *save;
   84     cfmakeraw(&set);
   85     if (tcsetattr(0, TCSANOW, &set) < 0)
   86         die("Unable to set terminal attributes: %m");
   87 }
   88 
   89 void resize_pty(int pty) {
   90     struct winsize sz;
   91     if (ioctl(0, TIOCGWINSZ, &sz) < 0) {
   92         // provide fake size to workaround some problems
   93         struct winsize defaultsize = {30, 80, 640, 480};
   94         if (ioctl(pty, TIOCSWINSZ, &defaultsize) < 0) {
   95             fprintf(stderr, "Cannot set terminal size\n");
   96         }
   97         return;
   98     }
   99     ioctl(pty, TIOCSWINSZ, &sz);
  100 }
  101 
  102 int writeall(int fd, const void *buf, ssize_t count) {
  103     ssize_t rv;
  104     while (count > 0) {
  105         rv = write(fd, buf, count);
  106         if (rv < 0) {
  107             if (errno == EINTR)
  108                 continue;
  109             return rv;
  110         }
  111         count -= rv;
  112         buf += rv;
  113     }
  114     return 0;
  115 }
  116 
  117 volatile sig_atomic_t winch_happened = 0;
  118 
  119 void do_winch(int signal) {
  120     winch_happened = 1;
  121 }
  122 
  123 void do_proxy(int pty) {
  124     char buf[4096];
  125     ssize_t count;
  126     fd_set set;
  127     sigset_t mask;
  128     sigset_t select_mask;
  129     struct sigaction sa;
  130 
  131     // Block WINCH while we're outside the select, but unblock it
  132     // while we're inside:
  133     sigemptyset(&mask);
  134     sigaddset(&mask, SIGWINCH);
  135     if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
  136         fprintf(stderr, "sigprocmask: %m");
  137         return;
  138     }
  139     sa.sa_handler = do_winch;
  140     sa.sa_flags = 0;
  141     sigemptyset(&sa.sa_mask);
  142     sigaction(SIGWINCH, &sa, NULL);
  143     resize_pty(pty);
  144 
  145     while (1) {
  146         if (winch_happened) {
  147             winch_happened = 0;
  148             resize_pty(pty);
  149         }
  150         FD_ZERO(&set);
  151         FD_SET(0, &set);
  152         FD_SET(pty, &set);
  153         sigemptyset(&select_mask);
  154         if (pselect(pty + 1, &set, NULL, NULL, NULL, &select_mask) < 0) {
  155             if (errno == EINTR)
  156                 continue;
  157             fprintf(stderr, "select: %m");
  158             return;
  159         }
  160         if (FD_ISSET(0, &set)) {
  161             count = read(0, buf, sizeof buf);
  162             if (count < 0)
  163                 return;
  164             writeall(pty, buf, count);
  165         }
  166         if (FD_ISSET(pty, &set)) {
  167             count = read(pty, buf, sizeof buf);
  168             if (count <= 0)
  169                 return;
  170             writeall(1, buf, count);
  171         }
  172     }
  173 }
  174 
  175 void usage(char *me) {
  176     fprintf(stderr, "Usage: %s [-s] PID\n", me);
  177     fprintf(stderr, "       %s -l|-L [COMMAND [ARGS]]\n", me);
  178     fprintf(stderr, "  -l    Create a new pty pair and print the name of the slave.\n");
  179     fprintf(stderr, "           if there are command-line arguments after -l\n");
  180     fprintf(stderr, "           they are executed with REPTYR_PTY set to path of pty.\n");
  181     fprintf(stderr, "  -L    Like '-l', but also redirect the child's stdio to the slave.\n");
  182     fprintf(stderr, "  -s    Attach fds 0-2 on the target, even if it is not attached to a tty.\n");
  183     fprintf(stderr, "  -T    Steal the entire terminal session of the target.\n");
  184     fprintf(stderr, "           [experimental] May be more reliable, and will attach all\n");
  185     fprintf(stderr, "           processes running on the terminal.\n");
  186     fprintf(stderr, "  -h    Print this help message and exit.\n");
  187     fprintf(stderr, "  -v    Print the version number and exit.\n");
  188     fprintf(stderr, "  -V    Print verbose debug output.\n");
  189 }
  190 
  191 int main(int argc, char **argv) {
  192     struct termios saved_termios;
  193     int pty;
  194     int opt;
  195     int err;
  196     int do_attach = 1;
  197     int force_stdio = 0;
  198     int do_steal = 0;
  199     int unattached_script_redirection = 0;
  200 
  201     while ((opt = getopt(argc, argv, "hlLsTvV")) != -1) {
  202         switch (opt) {
  203         case 'h':
  204             usage(argv[0]);
  205             return 0;
  206         case 'l':
  207             do_attach = 0;
  208             break;
  209         case 'L':
  210             do_attach = 0;
  211             unattached_script_redirection = 1;
  212             break;
  213         case 's':
  214             force_stdio = 1;
  215             break;
  216         case 'T':
  217             do_steal = 1;
  218             break;
  219         case 'v':
  220             printf("This is reptyr version %s.\n", REPTYR_VERSION);
  221             printf(" by Nelson Elhage <nelhage@nelhage.com>\n");
  222             printf("http://github.com/nelhage/reptyr/\n");
  223             return 0;
  224         case 'V':
  225             verbose = 1;
  226             break;
  227         default:
  228             usage(argv[0]);
  229             return 1;
  230         }
  231         if (opt == 'l' || opt == 'L') break; // the rest is a command line
  232     }
  233 
  234     if (do_attach && optind >= argc) {
  235         fprintf(stderr, "%s: No pid specified to attach\n", argv[0]);
  236         usage(argv[0]);
  237         return 1;
  238     }
  239 
  240     if (!do_steal) {
  241         if ((pty = get_pt()) < 0)
  242             die("Unable to allocate a new pseudo-terminal: %m");
  243         if (unlockpt(pty) < 0)
  244             die("Unable to unlockpt: %m");
  245         if (grantpt(pty) < 0)
  246             die("Unable to grantpt: %m");
  247     }
  248 
  249     if (do_attach) {
  250         char *endptr = NULL;
  251         errno = 0;
  252         long t = strtol(argv[optind], &endptr, 10);
  253         if (errno == ERANGE)
  254             die("Invalid pid: %m");
  255         if (*endptr)
  256             die("Invalid pid: must be integer");
  257         /* check for overflow/underflow */
  258         pid_t child = (pid_t)t;
  259         if (child < t || t < 1) /* pids can't be < 1, so no *real* underflow check */
  260             die("Invalid pid: %s", strerror(ERANGE));
  261 
  262         if (do_steal) {
  263             err = steal_pty(child, &pty);
  264         } else {
  265             err = attach_child(child, ptsname(pty), force_stdio);
  266         }
  267         if (err) {
  268             fprintf(stderr, "Unable to attach to pid %d: %s\n", child, strerror(err));
  269             if (err == EPERM) {
  270                 check_ptrace_scope();
  271             }
  272             return 1;
  273         }
  274     } else {
  275         printf("Opened a new pty: %s\n", ptsname(pty));
  276         fflush(stdout);
  277         if (argc > 2) {
  278             if (!fork()) {
  279                 setenv("REPTYR_PTY", ptsname(pty), 1);
  280                 if (unattached_script_redirection) {
  281                     int f;
  282                     setpgid(0, getppid());
  283                     setsid();
  284                     f = open(ptsname(pty), O_RDONLY, 0);
  285                     dup2(f, 0);
  286                     close(f);
  287                     f = open(ptsname(pty), O_WRONLY, 0);
  288                     dup2(f, 1);
  289                     dup2(f, 2);
  290                     close(f);
  291                 }
  292                 close(pty);
  293                 execvp(argv[2], argv + 2);
  294                 exit(1);
  295             }
  296         }
  297     }
  298 
  299     setup_raw(&saved_termios);
  300     do_proxy(pty);
  301     do {
  302         errno = 0;
  303         if (tcsetattr(0, TCSANOW, &saved_termios) && errno != EINTR)
  304             die("Unable to tcsetattr: %m");
  305     } while (errno == EINTR);
  306 
  307     return 0;
  308 }