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.
 
 
 
 
 

402 lines
11 KiB

  1. /*
  2. * neercs console-based window manager
  3. * Copyright (c) 2008-2010 Pascal Terjan <pterjan@linuxfr.org>
  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 _WIN32 && defined HAVE_GLOB_H
  16. #define _XOPEN_SOURCE 500 /* getsid() */
  17. #include <dirent.h>
  18. #include <errno.h>
  19. #include <fcntl.h>
  20. #include <glob.h>
  21. #include <libgen.h>
  22. #include <signal.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <stddef.h>
  26. #include <string.h>
  27. #include <unistd.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #include <sys/wait.h>
  31. #if defined HAVE_LINUX_KDEV_T_H
  32. # include <linux/kdev_t.h>
  33. # include <linux/major.h>
  34. #endif
  35. #include "neercs.h"
  36. #include "mytrace.h"
  37. int grab_process(long pid, char *ptyname, int ptyfd, int *newpid)
  38. {
  39. #if defined HAVE_LINUX_KDEV_T_H
  40. char fdstr[1024];
  41. struct mytrace *parent, *child;
  42. int i = 0, fd = 0, ret;
  43. char to_open[128];
  44. int mode[128];
  45. int fds[128];
  46. struct stat stat_buf;
  47. struct termios tos;
  48. int validtos = 0;
  49. DIR *fddir;
  50. struct dirent *fddirent;
  51. debug("pty is %s", ptyname);
  52. parent = mytrace_attach(pid);
  53. if (!parent)
  54. {
  55. fprintf(stderr, "Cannot access process %ld\n", pid);
  56. return -1;
  57. }
  58. child = mytrace_fork(parent);
  59. snprintf(fdstr, sizeof(fdstr), "/proc/%ld/fd", pid);
  60. fddir = opendir(fdstr);
  61. /* Look for file descriptors that are PTYs */
  62. while ((fddirent = readdir(fddir)) && i < (int)sizeof(to_open) - 1)
  63. {
  64. fd = atoi(fddirent->d_name);
  65. fds[i] = fd;
  66. to_open[i] = 0;
  67. lstat(fdstr, &stat_buf);
  68. if ((stat_buf.st_mode & S_IRUSR) && (stat_buf.st_mode & S_IWUSR))
  69. mode[i] = O_RDWR;
  70. else if (stat_buf.st_mode & S_IWUSR)
  71. mode[i] = O_WRONLY;
  72. else
  73. mode[i] = O_RDONLY;
  74. snprintf(fdstr, sizeof(fdstr), "/proc/%ld/fd/%s", pid,
  75. fddirent->d_name);
  76. if (stat(fdstr, &stat_buf) < 0)
  77. continue;
  78. if (!S_ISCHR(stat_buf.st_mode)
  79. || MAJOR(stat_buf.st_rdev) != UNIX98_PTY_SLAVE_MAJOR)
  80. continue;
  81. debug("found pty %d for pid %d", fd, pid);
  82. if (!validtos)
  83. {
  84. ret = mytrace_tcgets(child, fd, &tos);
  85. if (ret < 0)
  86. {
  87. perror("mytrace_tcgets");
  88. }
  89. else
  90. {
  91. validtos = 1;
  92. }
  93. }
  94. to_open[i] = 1;
  95. i++;
  96. }
  97. closedir(fddir);
  98. if (i >= (int)sizeof(to_open) - 1)
  99. {
  100. fprintf(stderr, "too many open pty\n");
  101. mytrace_detach(child);
  102. return -1;
  103. }
  104. ret = mytrace_exec(parent, "/usr/bin/reset");
  105. if (ret < 0)
  106. mytrace_exit(parent, 0);
  107. mytrace_detach(parent);
  108. waitpid(pid, NULL, 0); /* Wait for reset to finish before displaying */
  109. mytrace_write(child, 2, "\033[H\033[2J", 7);
  110. mytrace_write(child, 2, "\n[Process stolen by neercs]\r\n\n", 30);
  111. pid = mytrace_getpid(child);
  112. *newpid = pid;
  113. /* Set the process's session ID */
  114. debug("Running setsid on process %ld (sid=%d)", pid, getsid(pid));
  115. ret = mytrace_setpgid(child, 0, getsid(pid));
  116. if (ret < 0)
  117. {
  118. fprintf(stderr, "syscall setpgid failed\n");
  119. mytrace_detach(child);
  120. return -1;
  121. }
  122. if (ret != 0)
  123. {
  124. fprintf(stderr, "setpgid returned %d\n", ret);
  125. mytrace_detach(child);
  126. return -1;
  127. }
  128. ret = mytrace_setsid(child);
  129. if (ret < 0)
  130. {
  131. fprintf(stderr, "syscall setsid failed\n");
  132. mytrace_detach(child);
  133. return -1;
  134. }
  135. debug("pid %ld has now sid %d", pid, getsid(pid));
  136. /* Reopen PTY file descriptors */
  137. for (; i >= 0; i--)
  138. {
  139. if (!to_open[i])
  140. continue;
  141. ret = mytrace_close(child, fds[i]);
  142. if (ret < 0)
  143. {
  144. perror("mytrace_close");
  145. continue;
  146. }
  147. fd = mytrace_open(child, ptyname, mode[i]);
  148. if (fd < 0)
  149. {
  150. perror("mytrace_open");
  151. continue;
  152. }
  153. /* FIXME Only needed once */
  154. mytrace_sctty(child, fd);
  155. if (validtos)
  156. {
  157. ret = mytrace_tcsets(child, fd, &tos);
  158. if (ret < 0)
  159. {
  160. perror("mytrace_tcsets");
  161. }
  162. validtos = 0;
  163. }
  164. ret = mytrace_dup2(child, fd, fds[i]);
  165. if (ret < 0)
  166. {
  167. perror("mytrace_dup2");
  168. }
  169. }
  170. kill(pid, SIGWINCH);
  171. mytrace_detach(child);
  172. close(ptyfd);
  173. return 0;
  174. #else
  175. errno = ENOSYS;
  176. return -1;
  177. #endif
  178. }
  179. struct process
  180. {
  181. long pid;
  182. char *cmdline;
  183. };
  184. static int list_process(struct process **process_list)
  185. {
  186. glob_t pglob;
  187. unsigned int i, n = 0;
  188. glob("/proc/[0-9]*", GLOB_NOSORT, NULL, &pglob);
  189. *process_list = malloc(pglob.gl_pathc * sizeof(struct process));
  190. for (i = 0; i < pglob.gl_pathc; i++)
  191. {
  192. glob_t pglob2;
  193. unsigned int j;
  194. char *fds;
  195. (*process_list)[n].pid = atoi(basename(pglob.gl_pathv[i]));
  196. /* Don't allow grabbing ourselves */
  197. if ((*process_list)[n].pid == getpid())
  198. continue;
  199. /* FIXME check value of r */
  200. int r = asprintf(&fds, "%s/fd/*", pglob.gl_pathv[i]);
  201. (void) r;
  202. glob(fds, GLOB_NOSORT, NULL, &pglob2);
  203. free(fds);
  204. for (j = 0; j < pglob2.gl_pathc; j++)
  205. {
  206. char path[4096];
  207. ptrdiff_t l = readlink(pglob2.gl_pathv[j], path, sizeof(path));
  208. if (l <= 0)
  209. continue;
  210. path[l] = '\0';
  211. if (strstr(path, "/dev/pt"))
  212. {
  213. char *cmdfile;
  214. int fd;
  215. /* FIXME check value of r */
  216. r = asprintf(&cmdfile, "%s/cmdline", pglob.gl_pathv[i]);
  217. (void) r;
  218. fd = open(cmdfile, O_RDONLY);
  219. free(cmdfile);
  220. if (fd)
  221. {
  222. /* FIXME check value of r */
  223. r = read(fd, path, sizeof(path));
  224. (void) r;
  225. (*process_list)[n].cmdline = strdup(path);
  226. close(fd);
  227. n++;
  228. break;
  229. }
  230. }
  231. }
  232. globfree(&pglob2);
  233. }
  234. globfree(&pglob);
  235. return n;
  236. }
  237. long select_process(struct screen_list *screen_list)
  238. {
  239. caca_event_t ev;
  240. enum caca_event_type t;
  241. int current_line = 1;
  242. int refresh = 1;
  243. int nb_process, i;
  244. int ret = 0;
  245. int start = 0;
  246. struct process *process_list;
  247. nb_process = list_process(&process_list);
  248. screen_list->cv = caca_create_canvas(0, 0);
  249. screen_list->dp = caca_create_display(screen_list->cv);
  250. if (!screen_list->dp)
  251. goto end;
  252. caca_set_cursor(screen_list->dp, 0);
  253. caca_set_display_title(screen_list->dp, PACKAGE_STRING);
  254. while (1)
  255. {
  256. if (refresh)
  257. {
  258. caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE);
  259. caca_fill_box(screen_list->cv,
  260. 0, 0,
  261. caca_get_canvas_width(screen_list->cv),
  262. caca_get_canvas_height(screen_list->cv), '#');
  263. caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_BLUE);
  264. caca_draw_cp437_box(screen_list->cv,
  265. 0, 0,
  266. caca_get_canvas_width(screen_list->cv),
  267. caca_get_canvas_height(screen_list->cv));
  268. caca_printf(screen_list->cv, 2, 2,
  269. "Please select a process to grab:");
  270. for (i = 0;
  271. i < nb_process
  272. && i < caca_get_canvas_height(screen_list->cv) - 4; i++)
  273. {
  274. if (i == current_line - 1)
  275. {
  276. caca_set_attr(screen_list->cv, CACA_BOLD);
  277. caca_set_color_ansi(screen_list->cv, CACA_GREEN,
  278. CACA_BLUE);
  279. caca_put_char(screen_list->cv, 1, i + 3, '>');
  280. }
  281. else
  282. {
  283. caca_set_attr(screen_list->cv, 0);
  284. caca_set_color_ansi(screen_list->cv, CACA_LIGHTGRAY,
  285. CACA_BLUE);
  286. caca_put_char(screen_list->cv, 1, i + 3, ' ');
  287. }
  288. caca_printf(screen_list->cv,
  289. 3, i + 3,
  290. "%5d %s",
  291. process_list[i + start].pid,
  292. process_list[i + start].cmdline);
  293. }
  294. caca_refresh_display(screen_list->dp);
  295. refresh = 0;
  296. }
  297. if (!caca_get_event(screen_list->dp,
  298. CACA_EVENT_KEY_PRESS
  299. | CACA_EVENT_RESIZE | CACA_EVENT_QUIT, &ev, 10000))
  300. continue;
  301. t = caca_get_event_type(&ev);
  302. if (t & CACA_EVENT_KEY_PRESS)
  303. {
  304. unsigned int c = caca_get_event_key_ch(&ev);
  305. switch (c)
  306. {
  307. case CACA_KEY_UP:
  308. if (current_line > 1)
  309. current_line--;
  310. if (current_line < start && start > 0)
  311. start--;
  312. break;
  313. case CACA_KEY_DOWN:
  314. if (current_line < nb_process)
  315. current_line++;
  316. if (current_line >
  317. start + caca_get_canvas_height(screen_list->cv) - 3)
  318. start++;
  319. break;
  320. case CACA_KEY_RETURN:
  321. ret = process_list[current_line - 1].pid;
  322. goto end;
  323. break;
  324. case CACA_KEY_ESCAPE:
  325. goto end;
  326. break;
  327. default:
  328. break;
  329. }
  330. refresh = 1;
  331. }
  332. else if (t & CACA_EVENT_RESIZE)
  333. {
  334. refresh = 1;
  335. }
  336. else if (t & CACA_EVENT_QUIT)
  337. goto end;
  338. }
  339. end:
  340. if (screen_list->dp)
  341. {
  342. caca_free_display(screen_list->dp);
  343. screen_list->dp = NULL;
  344. }
  345. if (screen_list->cv)
  346. {
  347. caca_free_canvas(screen_list->cv);
  348. screen_list->cv = NULL;
  349. }
  350. if (nb_process > 0)
  351. {
  352. for (i = 0; i < nb_process; i++)
  353. {
  354. free(process_list[i].cmdline);
  355. }
  356. free(process_list);
  357. }
  358. return ret;
  359. }
  360. #endif