25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 

239 satır
4.9 KiB

  1. /*
  2. * neercs console-based window manager
  3. * Copyright (c) 2006-2012 Sam Hocevar <sam@hocevar.net>
  4. * All Rights Reserved
  5. *
  6. * This program is free software. It comes without any warranty, to
  7. * the extent permitted by applicable law. You can redistribute it
  8. * and/or modify it under the terms of the Do What The Fuck You Want
  9. * To Public License, Version 2, as published by Sam Hocevar. See
  10. * http://sam.zoy.org/wtfpl/COPYING for more details.
  11. */
  12. #if defined HAVE_CONFIG_H
  13. # include "config.h"
  14. #endif
  15. #if defined HAVE_FORKPTY
  16. # define _XOPEN_SOURCE
  17. # include <stdlib.h>
  18. # include <stdio.h>
  19. # include <string.h>
  20. # include <sys/ioctl.h>
  21. # include <sys/types.h>
  22. # include <termios.h>
  23. # if defined HAVE_PTY_H
  24. # include <pty.h> /* for openpty and forkpty */
  25. # elif defined HAVE_UTIL_H
  26. # include <util.h> /* for OS X, OpenBSD and NetBSD */
  27. # elif defined HAVE_LIBUTIL_H
  28. # include <libutil.h> /* for FreeBSD */
  29. # endif
  30. # include <unistd.h>
  31. # include <fcntl.h>
  32. #endif
  33. #include "core.h"
  34. #include "loldebug.h"
  35. using namespace std;
  36. using namespace lol;
  37. #include "../neercs.h"
  38. Pty::Pty()
  39. : m_fd(-1),
  40. m_pid(-1),
  41. m_eof(false),
  42. m_unread_data(0),
  43. m_unread_len(0)
  44. {
  45. ;
  46. }
  47. Pty::~Pty()
  48. {
  49. #if defined HAVE_FORKPTY
  50. delete[] m_unread_data;
  51. if (m_fd >= 0)
  52. {
  53. close((int)m_fd);
  54. }
  55. #endif
  56. }
  57. void Pty::Run(char const *command, ivec2 size)
  58. {
  59. #if defined HAVE_FORKPTY
  60. int fd;
  61. pid_t pid;
  62. m_pid = -1;
  63. m_fd = -1;
  64. pid = forkpty(&fd, NULL, NULL, NULL);
  65. if (pid < 0)
  66. {
  67. fprintf(stderr, "forkpty() error\n");
  68. return;
  69. }
  70. else if (pid == 0)
  71. {
  72. SetWindowSize(size, 0);
  73. /* putenv() eats the string, they need to be writable */
  74. static char tmp1[] = "CACA_DRIVER=slang";
  75. static char tmp2[] = "TERM=xterm";
  76. putenv(tmp1);
  77. putenv(tmp2);
  78. m_argv[0] = command;
  79. m_argv[1] = NULL;
  80. /* The following const cast is valid. The Open Group Base
  81. * Specification guarantees that the objects are completely
  82. * constant. */
  83. execvp(command, const_cast<char * const *>(m_argv));
  84. fprintf(stderr, "execvp() error\n");
  85. return;
  86. }
  87. fcntl(fd, F_SETFL, O_NDELAY);
  88. m_pid = pid;
  89. m_fd = fd;
  90. #endif
  91. }
  92. bool Pty::IsEof() const
  93. {
  94. return m_eof;
  95. }
  96. size_t Pty::ReadData(char *data, size_t maxlen)
  97. {
  98. #if defined HAVE_FORKPTY
  99. size_t sent = 0;
  100. /* Do we have data from previous call? */
  101. if (m_unread_len)
  102. {
  103. size_t tocopy = min(maxlen, m_unread_len);
  104. memcpy(data, m_unread_data, tocopy);
  105. data += tocopy;
  106. sent += tocopy;
  107. maxlen -= tocopy;
  108. if (tocopy < m_unread_len)
  109. {
  110. m_unread_len -= tocopy;
  111. memmove(m_unread_data, m_unread_data + tocopy, m_unread_len);
  112. }
  113. else
  114. {
  115. delete[] m_unread_data;
  116. m_unread_data = 0;
  117. m_unread_len = 0;
  118. }
  119. }
  120. fd_set fdset;
  121. int maxfd = -1;
  122. FD_ZERO(&fdset);
  123. if (m_fd >= 0)
  124. {
  125. FD_SET((int)m_fd, &fdset);
  126. maxfd = std::max(maxfd, (int)m_fd);
  127. }
  128. if (maxfd >= 0)
  129. {
  130. struct timeval tv;
  131. tv.tv_sec = 0;
  132. tv.tv_usec = 50000;
  133. int ret = select(maxfd + 1, &fdset, NULL, NULL, &tv);
  134. if (ret < 0)
  135. {
  136. Log::Error("cannot read from PTY\n");
  137. m_eof = true;
  138. return 0;
  139. }
  140. else if (ret)
  141. {
  142. if (FD_ISSET((int)m_fd, &fdset))
  143. {
  144. ssize_t nr = read((int)m_fd, data, maxlen);
  145. /* Data available but zero-length read: EOF */
  146. if (nr <= 0)
  147. m_eof = true;
  148. else
  149. sent += nr;
  150. if (sent >= 0)
  151. return sent;
  152. }
  153. }
  154. }
  155. #endif
  156. return 0;
  157. }
  158. void Pty::UnreadData(char *data, size_t len)
  159. {
  160. #if defined HAVE_FORKPTY
  161. /* Prepare unread buffer */
  162. if (m_unread_data)
  163. {
  164. char *tmp = new char[m_unread_len + len];
  165. memcpy(tmp + len, m_unread_data, m_unread_len);
  166. delete[] m_unread_data;
  167. m_unread_data = tmp;
  168. m_unread_len += len;
  169. }
  170. else
  171. {
  172. m_unread_data = new char[len];
  173. m_unread_len = len;
  174. }
  175. /* Copy data to the unread buffer */
  176. memcpy(m_unread_data, data, len);
  177. #endif
  178. }
  179. size_t Pty::WriteData(char const *data, size_t len)
  180. {
  181. #if defined HAVE_FORKPTY
  182. /* FIXME: can we be more naive than that? */
  183. return write((int)m_fd, data, len);
  184. #endif
  185. return 0;
  186. }
  187. void Pty::SetWindowSize(ivec2 size, int64_t fd /* = -1 */)
  188. {
  189. #if defined HAVE_FORKPTY
  190. if (m_size == size)
  191. return;
  192. if (fd < 0)
  193. fd = m_fd;
  194. m_size = size;
  195. struct winsize ws;
  196. memset(&ws, 0, sizeof(ws));
  197. ws.ws_row = size.y;
  198. ws.ws_col = size.x;
  199. ioctl((int)fd, TIOCSWINSZ, (char *)&ws);
  200. #endif
  201. }