Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 

243 lignes
5.1 KiB

  1. /*
  2. * neercs console-based window manager
  3. * Copyright (c) 2006-2013 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://www.wtfpl.net/ 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. m_size(-1, -1)
  45. {
  46. ;
  47. }
  48. Pty::~Pty()
  49. {
  50. #if defined HAVE_FORKPTY
  51. delete[] m_unread_data;
  52. if (m_fd >= 0)
  53. {
  54. close((int)m_fd);
  55. }
  56. #endif
  57. }
  58. void Pty::Run(char const *command, ivec2 size)
  59. {
  60. #if defined HAVE_FORKPTY
  61. int fd;
  62. pid_t pid;
  63. m_pid = -1;
  64. m_fd = -1;
  65. pid = forkpty(&fd, NULL, NULL, NULL);
  66. if (pid < 0)
  67. {
  68. fprintf(stderr, "forkpty() error\n");
  69. return;
  70. }
  71. else if (pid == 0)
  72. {
  73. SetWindowSize(size, 0);
  74. /* putenv() eats the string, they need to be writable */
  75. static char tmp1[] = "CACA_DRIVER=slang";
  76. static char tmp2[] = "TERM=xterm";
  77. putenv(tmp1);
  78. putenv(tmp2);
  79. m_argv[0] = command;
  80. m_argv[1] = NULL;
  81. /* The following const cast is valid. The Open Group Base
  82. * Specification guarantees that the objects are completely
  83. * constant. */
  84. execvp(command, const_cast<char * const *>(m_argv));
  85. fprintf(stderr, "execvp() error\n");
  86. return;
  87. }
  88. fcntl(fd, F_SETFL, O_NDELAY);
  89. m_pid = pid;
  90. m_fd = fd;
  91. #endif
  92. }
  93. bool Pty::IsEof() const
  94. {
  95. return m_eof;
  96. }
  97. /* Read data from the PTY. We only perform one read() call so that the
  98. * caller can decide whether to ask for more data or not. This lets us
  99. * prioritise data in some way. */
  100. size_t Pty::ReadData(char *data, size_t maxlen)
  101. {
  102. #if defined HAVE_FORKPTY
  103. size_t sent = 0;
  104. /* Do we have data from previous call? */
  105. if (m_unread_len)
  106. {
  107. size_t tocopy = min(maxlen, m_unread_len);
  108. memcpy(data, m_unread_data, tocopy);
  109. data += tocopy;
  110. sent += tocopy;
  111. maxlen -= tocopy;
  112. if (tocopy < m_unread_len)
  113. {
  114. m_unread_len -= tocopy;
  115. memmove(m_unread_data, m_unread_data + tocopy, m_unread_len);
  116. }
  117. else
  118. {
  119. delete[] m_unread_data;
  120. m_unread_data = 0;
  121. m_unread_len = 0;
  122. }
  123. }
  124. fd_set fdset;
  125. int maxfd = -1;
  126. FD_ZERO(&fdset);
  127. if (m_fd >= 0)
  128. {
  129. FD_SET((int)m_fd, &fdset);
  130. maxfd = std::max(maxfd, (int)m_fd);
  131. }
  132. if (maxfd >= 0)
  133. {
  134. struct timeval tv;
  135. tv.tv_sec = 0;
  136. tv.tv_usec = 50000;
  137. int ret = select(maxfd + 1, &fdset, NULL, NULL, &tv);
  138. if (ret < 0)
  139. {
  140. Log::Error("cannot read from PTY\n");
  141. m_eof = true;
  142. return 0;
  143. }
  144. else if (ret)
  145. {
  146. if (FD_ISSET((int)m_fd, &fdset))
  147. {
  148. ssize_t nr = read((int)m_fd, data, maxlen);
  149. /* Data available but zero-length read: EOF */
  150. if (nr <= 0)
  151. m_eof = true;
  152. else
  153. sent += nr;
  154. if (sent >= 0)
  155. return sent;
  156. }
  157. }
  158. }
  159. #endif
  160. return 0;
  161. }
  162. void Pty::UnreadData(char *data, size_t len)
  163. {
  164. #if defined HAVE_FORKPTY
  165. /* Prepare unread buffer */
  166. if (m_unread_data)
  167. {
  168. char *tmp = new char[m_unread_len + len];
  169. memcpy(tmp + len, m_unread_data, m_unread_len);
  170. delete[] m_unread_data;
  171. m_unread_data = tmp;
  172. m_unread_len += len;
  173. }
  174. else
  175. {
  176. m_unread_data = new char[len];
  177. m_unread_len = len;
  178. }
  179. /* Copy data to the unread buffer */
  180. memcpy(m_unread_data, data, len);
  181. #endif
  182. }
  183. size_t Pty::WriteData(char const *data, size_t len)
  184. {
  185. #if defined HAVE_FORKPTY
  186. /* FIXME: can we be more naive than that? */
  187. return write((int)m_fd, data, len);
  188. #endif
  189. return 0;
  190. }
  191. void Pty::SetWindowSize(ivec2 size, int64_t fd /* = -1 */)
  192. {
  193. #if defined HAVE_FORKPTY
  194. if (m_size == size)
  195. return;
  196. if (fd < 0)
  197. fd = m_fd;
  198. m_size = size;
  199. struct winsize ws;
  200. memset(&ws, 0, sizeof(ws));
  201. ws.ws_row = size.y;
  202. ws.ws_col = size.x;
  203. ioctl((int)fd, TIOCSWINSZ, (char *)&ws);
  204. #endif
  205. }