Another copy of my dotfiles. Because I don't completely trust GitHub.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

156 lines
2.7 KiB

  1. #include <sys/wait.h>
  2. #include <errno.h>
  3. #include <inttypes.h>
  4. #include <limits.h>
  5. #include <poll.h>
  6. #include <stdarg.h>
  7. #include <stdbool.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <termios.h>
  12. #include <unistd.h>
  13. #if defined(__linux)
  14. #include <pty.h>
  15. #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
  16. #include <util.h>
  17. #elif defined(__FreeBSD__) || defined(__DragonFly__)
  18. #include <libutil.h>
  19. #endif
  20. void
  21. die(const char *fmt, ...)
  22. {
  23. va_list ap;
  24. va_start(ap, fmt);
  25. vfprintf(stderr, fmt, ap);
  26. va_end(ap);
  27. if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
  28. fputc(' ', stderr);
  29. perror(NULL);
  30. } else {
  31. fputc('\n', stderr);
  32. }
  33. exit(EXIT_FAILURE);
  34. }
  35. void
  36. usage(void)
  37. {
  38. fputs("ptty [-C] [-c cols] [-r rows] cmd\n", stderr);
  39. exit(EXIT_FAILURE);
  40. }
  41. int
  42. main(int argc, char *argv[])
  43. {
  44. struct winsize ws = {.ws_row = 25, .ws_col = 80, 0, 0};
  45. int ch;
  46. bool closeflag = false;
  47. while ((ch = getopt(argc, argv, "c:r:Ch")) != -1) {
  48. switch (ch) {
  49. case 'c': /* cols */
  50. ws.ws_col = strtoimax(optarg, NULL, 10);
  51. if (errno != 0)
  52. die("strtoimax: %s", optarg);
  53. break;
  54. case 'r': /* lines */
  55. ws.ws_row = strtoimax(optarg, NULL, 10);
  56. if (errno != 0)
  57. die("strtoimax: %s", optarg);
  58. break;
  59. case 'C':
  60. closeflag = true;
  61. break;
  62. case 'h':
  63. default:
  64. usage();
  65. }
  66. }
  67. argc -= optind;
  68. argv += optind;
  69. if (argc < 1)
  70. usage();
  71. int mfd;
  72. pid_t child = forkpty(&mfd, NULL, NULL, &ws);
  73. switch (child) {
  74. case -1:
  75. die("forkpty");
  76. case 0: /* child */
  77. execvp(argv[0], argv);
  78. die("exec");
  79. }
  80. /* parent */
  81. if (closeflag && close(mfd) == -1)
  82. die("close:");
  83. int pfds = 2;
  84. struct pollfd pfd[2] = {
  85. { STDIN_FILENO, POLLIN, 0},
  86. { mfd, POLLIN, 0}
  87. };
  88. for (;;) {
  89. char buf[BUFSIZ];
  90. ssize_t n;
  91. int r;
  92. if ((r = poll(pfd, pfds, -1)) == -1)
  93. die("poll:");
  94. if (pfd[0].revents & POLLIN) {
  95. if ((n = read(STDIN_FILENO, buf, sizeof buf)) == -1)
  96. die("read:");
  97. if (n == 0) {
  98. pfd[0].fd = -1;
  99. if (close(mfd) == -1)
  100. die("close:");
  101. break;
  102. }
  103. if (write(mfd, buf, n) == -1)
  104. die("write:");
  105. }
  106. if (pfd[1].revents & POLLIN) {
  107. if ((n = read(mfd, buf, sizeof(buf)-1)) == -1)
  108. die("read:");
  109. if (n == 0) break;
  110. buf[n] = '\0';
  111. /* handle cursor position request */
  112. if (strcmp("\033[6n", buf) == 0) {
  113. dprintf(mfd, "\033[25;1R");
  114. continue;
  115. }
  116. if (write(STDOUT_FILENO, buf, n) == -1)
  117. die("write:");
  118. }
  119. if (pfd[0].revents & POLLHUP) {
  120. pfd[0].fd = -1;
  121. if (close(mfd) == -1)
  122. die("close:");
  123. break;
  124. }
  125. if (pfd[1].revents & POLLHUP)
  126. break;
  127. }
  128. int status;
  129. if (waitpid(child, &status, 0) != child)
  130. die("waitpid:");
  131. return WEXITSTATUS(status);
  132. }