ptty.c 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #include <sys/wait.h>
  2. #include <errno.h>
  3. #include <inttypes.h>
  4. #include <limits.h>
  5. #include <stdarg.h>
  6. #include <stdbool.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <termios.h>
  11. #include <unistd.h>
  12. #if defined(__linux)
  13. #include <pty.h>
  14. #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
  15. #include <util.h>
  16. #elif defined(__FreeBSD__) || defined(__DragonFly__)
  17. #include <libutil.h>
  18. #endif
  19. void
  20. die(const char *fmt, ...)
  21. {
  22. va_list ap;
  23. va_start(ap, fmt);
  24. vfprintf(stderr, fmt, ap);
  25. va_end(ap);
  26. if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
  27. fputc(' ', stderr);
  28. perror(NULL);
  29. } else {
  30. fputc('\n', stderr);
  31. }
  32. exit(EXIT_FAILURE);
  33. }
  34. void
  35. usage(void)
  36. {
  37. fputs("ptty [-C] [-c cols] [-r rows] cmd\n", stderr);
  38. exit(EXIT_FAILURE);
  39. }
  40. int
  41. main(int argc, char *argv[])
  42. {
  43. struct winsize ws = {.ws_row = 25, .ws_col = 80, 0, 0};
  44. int ch;
  45. bool closeflag = false;
  46. while ((ch = getopt(argc, argv, "c:r:Ch")) != -1) {
  47. switch (ch) {
  48. case 'c': /* cols */
  49. ws.ws_col = strtoimax(optarg, NULL, 10);
  50. if (errno != 0)
  51. die("strtoimax: %s", optarg);
  52. break;
  53. case 'r': /* lines */
  54. ws.ws_row = strtoimax(optarg, NULL, 10);
  55. if (errno != 0)
  56. die("strtoimax: %s", optarg);
  57. break;
  58. case 'C':
  59. closeflag = true;
  60. break;
  61. case 'h':
  62. default:
  63. usage();
  64. }
  65. }
  66. argc -= optind;
  67. argv += optind;
  68. if (argc < 1)
  69. usage();
  70. int mfd;
  71. pid_t pid = forkpty(&mfd, NULL, NULL, &ws);
  72. switch (pid) {
  73. case -1:
  74. die("forkpty");
  75. case 0: /* child */
  76. execvp(argv[0], argv);
  77. die("exec");
  78. }
  79. /* parent */
  80. FILE *fh = fdopen(mfd, "rw");
  81. if (fh == NULL)
  82. die("fdopen");
  83. if (closeflag && close(mfd) == -1)
  84. die("close:");
  85. char buf[BUFSIZ];
  86. while (fgets(buf, sizeof buf, fh) != NULL);
  87. int status;
  88. waitpid(pid, &status, 0);
  89. return WEXITSTATUS(status);
  90. }