source: trunk/tools/neercs/old/grab.c @ 2090

Last change on this file since 2090 was 2090, checked in by sam, 7 years ago

neercs: added a better check for forkpty(), and moved the GL_POINTS
size and texture logic to the vertex shader.

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