source: neercs/trunk/src/grab.c @ 4001

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