source: neercs/trunk/src/main.c @ 2588

Last change on this file since 2588 was 2588, checked in by Pascal Terjan, 12 years ago
  • Rewrote detach handling, enjoy silent neercs
  • Property svn:keywords set to Id
File size: 13.9 KB
Line 
1/*
2 *  neercs        console-based window manager
3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
4 *                2008 Jean-Yves Lamoureux <jylam@lnxscene.org>
5 *                2008 Pascal Terjan <pterjan@linuxfr.org>
6 *                All Rights Reserved
7 *
8 *  $Id: main.c 2588 2008-07-26 23:17:04Z pterjan $
9 *
10 *  This program is free software. It comes without any warranty, to
11 *  the extent permitted by applicable law. You can redistribute it
12 *  and/or modify it under the terms of the Do What The Fuck You Want
13 *  To Public License, Version 2, as published by Sam Hocevar. See
14 *  http://sam.zoy.org/wtfpl/COPYING for more details.
15 */
16
17#include "config.h"
18
19#include <stdio.h>
20#include <string.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <fcntl.h>
24#include <signal.h>
25#include <sys/ioctl.h>
26#include <sys/types.h>
27#include <sys/wait.h>
28#include <sys/time.h>
29#include <time.h>
30#include <pwd.h>
31
32
33#if !defined HAVE_GETOPT_LONG
34#   include "mygetopt.h"
35#elif defined HAVE_GETOPT_H
36#   include <getopt.h>
37#endif
38#if defined HAVE_GETOPT_LONG
39#   define mygetopt getopt_long
40#   define myoptind optind
41#   define myoptarg optarg
42#   define myoption option
43#endif
44#include <errno.h>
45#include <cucul.h>
46#include <caca.h>
47
48#include "neercs.h"
49
50
51void version(void)
52{
53    printf("%s\n", PACKAGE_STRING);
54    printf("Copyright (C) 2006, 2008 Sam Hocevar <sam@zoy.org>\n");
55    printf("                         Jean-Yves Lamoureux <jylam@lnxscene.org>\n\n");
56    printf("This is free software.  You may redistribute copies of it under the\n");
57    printf("terms of the Do What The Fuck You Want To Public License, Version 2\n");
58    printf("<http://sam.zoy.org/wtfpl/>.\n");
59    printf("There is NO WARRANTY, to the extent permitted by law.\n");
60    printf("\n");
61    printf("For more informations, visit http://libcaca.zoy.org/wiki/neercs\n");
62}
63
64void usage(int argc, char **argv)
65{
66    printf("%s\n", PACKAGE_STRING);
67    printf("Usage : %s [command1] [command2] ... [commandN]\n", argv[0]);
68    printf("Example : %s zsh top \n\n", argv[0]);
69    printf("Options :\n");
70    printf("\t--config\t-c <file>\t\tuse given config file\n");
71    printf("\t--pid\t\t-P <pid>\t\tgrab <pid>\n");
72    printf("\t\t\t-r [session]\t\treattach to a detached neercs\n");
73    printf("\t\t\t-R [session]\t\treattach if possible, otherwise start a new session\n");
74    printf("\t\t\t-S <name>\t\tname this session <name> instead of <pid>\n");
75    printf("\t--version\t-v \t\t\tdisplay version and exit\n");
76    printf("\t--help\t\t-h \t\t\tthis help\n");
77}
78
79int main(int argc, char **argv)
80{
81    struct screen_list *screen_list = NULL;
82    struct passwd *user_info;
83    char *user_path = NULL, *user_dir = NULL;
84    int i, args, s=0;
85    int refresh = 1;
86    long long unsigned int last_key_time = 0;
87    int mainret = 0;
88    int attach = 0, forceattach = 0;
89    int *to_grab = NULL;
90    char **to_start = NULL;
91    int nb_to_grab = 0;
92
93    screen_list = create_screen_list();
94    screen_list->default_shell = getenv("SHELL");
95
96    args = argc -1;
97    if(screen_list->default_shell == NULL  && args <= 0)
98    {
99        fprintf(stderr, "Environment variable SHELL not set and no arguments given. kthxbye.\n");
100        return -1;
101    }
102
103    if(args==0)
104        args = 1;
105
106    /* Build local config file path */
107    user_dir = getenv("HOME");
108    if(!user_dir)
109    {
110        user_info = getpwuid(getuid());
111        if(user_info)
112        {
113            user_dir = user_info->pw_dir;
114        }
115    }
116    if(user_dir)
117    {
118        user_path = malloc(strlen(user_dir) + strlen("/.neercsrc") + 1);
119        sprintf(user_path, "%s/%s", user_dir, ".neercsrc");
120    }
121
122
123    screen_list->recurrent_list = (struct recurrent_list*) malloc(sizeof(struct recurrent_list));
124    screen_list->recurrent_list->recurrent = (struct recurrent**) malloc(sizeof(struct recurrent*));
125    if(!screen_list->recurrent_list->recurrent)
126    {
127        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
128        return -1;
129    }
130    screen_list->recurrent_list->count = 0;
131
132    for(;;)
133    {
134        int option_index = 0;
135        int pidopt;
136        static struct myoption long_options[] =
137            {
138                { "config",      1, NULL, 'c' },
139#if defined USE_GRAB
140                { "pid",         1, NULL, 'P' },
141#endif
142                { "help",        0, NULL, 'h' },
143                { "version",     0, NULL, 'v' },
144            };
145#if defined USE_GRAB
146        int c = mygetopt(argc, argv, "c:S:R::r::P:hv", long_options, &option_index);
147#else
148        int c = mygetopt(argc, argv, "c:S:R::r::hv", long_options, &option_index);
149#endif
150        if(c == -1)
151            break;
152
153        switch(c)
154        {
155        case 'c': /* --config */
156            if(user_path)
157                free(user_path);
158            user_path = strdup(myoptarg);
159            s+=2;
160            break;
161        case 'S':
162            if(!screen_list->session_name)
163                screen_list->session_name = strdup(myoptarg);
164            s+=2;
165            break;
166        case 'P': /* --pid */
167            pidopt = atoi(myoptarg);
168            if(pidopt <= 0)
169            {
170                fprintf(stderr, "Invalid pid %d\n", pidopt);
171                if(to_grab)
172                    free(to_grab);
173                return -1;
174            }
175            if(!to_grab)
176            {
177                /* At most argc-1-s times -P <pid> + final 0 */
178                to_grab = (int *)malloc(((argc-1-s)/2+1)*sizeof(int));
179                if(!to_grab)
180                {
181                    fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
182                    return -1;
183                }
184            }
185            to_grab[nb_to_grab++] = pidopt;
186            to_grab[nb_to_grab] = 0;
187            s+=2;
188            break;
189        case 'r':
190            forceattach = 1;
191        case 'R':
192            if(attach)
193            {
194                fprintf(stderr, "Attaching can only be requested once\n");
195                return -1;
196            }
197            if(myoptarg)
198            {
199                if(screen_list->session_name)
200                    free(screen_list->session_name);
201                screen_list->session_name = strdup(myoptarg);
202                s+=1;
203            }
204            attach = 1;
205            s+=1;
206            break;
207        case 'h': /* --help */
208            usage(argc, argv);
209            return 0;
210            break;
211        case 'v': /* --version */
212            version();
213            return 0;
214            break;
215        default:
216            fprintf(stderr, "Unknown argument #%d\n", myoptind);
217            return -1;
218            break;
219        }
220    }
221
222    if(s < argc - 1)
223    {
224        to_start = (char**)malloc((argc-s)*sizeof(char*));
225        if(!to_start)
226        {
227            fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
228            return -1;
229        }
230        for(i=0; i<(argc-1) - s; i++)
231        {
232            to_start[i] = strdup(argv[i+s+1]);
233        }
234        to_start[argc-1-s] = NULL;
235    }
236
237    /* Read global configuration first */
238    read_configuration_file("/etc/neercsrc", screen_list);
239
240    /* Then local one  */
241    if(user_path)
242    {
243        read_configuration_file(user_path, screen_list);
244        free(user_path);
245    }
246
247    if(attach)
248    {
249        char **sockets;
250        if(nb_to_grab || (argc-1 > s))
251        {
252            fprintf(stderr, "-R can not be associated with commands or pids!\n");
253            return -1;
254        }
255        sockets = list_sockets(screen_list->socket_dir, screen_list->session_name);
256        if(sockets && sockets[0])
257        {
258            char *session;
259            for(i=0; sockets[i]; i++);
260            i--;
261            session = connect_server(sockets[i], screen_list);
262            if(session)
263            {
264                request_attach(screen_list);
265                if(screen_list->session_name)
266                    free(screen_list->session_name);
267                screen_list->session_name = session;
268            }
269            else
270            {
271                fprintf(stderr, "Failed to attach!\n");
272                attach = 0;
273            }
274            for(i=0; sockets[i]; i++)
275                free(sockets[i]);
276            free(sockets);
277        }
278        else
279        {
280            fprintf(stderr, "No socket found!\n");
281            attach = 0;
282        }
283        if(forceattach && !attach)
284            return -1;
285    }
286
287    /* Build default session name */
288    if(!screen_list->session_name)
289    {
290        char mypid[32]; /* FIXME Compute the length of PID_MAX ? */
291        snprintf(mypid, 31, "%d", getpid());
292        mypid[31]= '\0';
293        screen_list->session_name = strdup(mypid);
294        if(!screen_list->session_name)
295        {
296            fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
297            return -1;
298        }
299    }
300
301    /* Fork the server if needed */
302    if(!attach)
303    {
304        pid_t pid;
305
306        screen_list->socket_path = build_socket_path(screen_list->socket_path, screen_list->session_name);
307
308        pid = fork();
309        if(pid < 0)
310        {
311            fprintf(stderr, "Failed to create child process\n");
312            return -1;
313        }
314        if(pid == 0)
315        {
316            int fd;
317            close(0);
318            close(1);
319            close(2);
320            fd = open("/dev/null", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
321            dup2(fd, 0);
322#ifndef DEBUG
323            dup2(fd, 1);
324            dup2(fd, 2);
325            if (fd > 2)
326                close(fd);
327#else
328            if(fd != 0)
329                close(fd);
330            fd = open("/tmp/log.txt", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
331            dup2(fd, 1);
332            dup2(fd, 2);
333            if (fd > 2)
334                close(fd);
335#endif
336            setsid();
337            return server_main(to_grab, to_start, screen_list);
338        }
339
340        free(connect_server(screen_list->socket_path, screen_list));
341    }
342
343    /* Create main canvas and associated caca window */
344    screen_list->cv = cucul_create_canvas(0, 0);
345    screen_list->dp = caca_create_display(screen_list->cv);
346    if(!screen_list->dp)
347        return 1;
348    caca_set_cursor(screen_list->dp, 1);
349    screen_list->width  = cucul_get_canvas_width(screen_list->cv);
350    screen_list->height = cucul_get_canvas_height(screen_list->cv) - ((screen_list->mini*6) + (screen_list->status));
351
352    last_key_time = get_us();
353
354    for(;;)
355    {
356        caca_event_t ev;
357        int ret = 0;
358        ssize_t n;
359        char buf[4097];
360
361        while (screen_list->socket && (n = read(screen_list->socket, buf, sizeof(buf)-1)) > 0)
362        {
363            buf[n] = 0;
364            debug("Received from server: %s", buf);
365            if(!strncmp("DETACH", buf, 6))
366            {
367                ret = 1;
368                break;
369            }
370            else if(!strncmp("REFRESH", buf, 7))
371            {
372                /* FIXME update the canvas first */
373                caca_refresh_display(screen_list->dp);
374            }
375            else if(!strncmp("CURSOR ", buf, 7))
376            {
377                caca_set_cursor(screen_list->dp, atoi(buf+7));
378            }
379            else if(!strncmp("TITLE ", buf, 6))
380            {
381                caca_set_display_title(screen_list->dp, buf+6);
382                caca_refresh_display(screen_list->dp);
383            }
384        }
385        if(ret)
386            break;
387
388        ret = caca_get_event(screen_list->dp, CACA_EVENT_ANY, &ev, 100000);
389        if(ret)
390            ret = send_event(ev, screen_list->socket);
391
392        if(ret)
393            break;
394    }
395
396    /* Clean up */
397    if(screen_list->dp)
398        caca_free_display(screen_list->dp);
399
400    cucul_free_canvas(screen_list->cv);
401
402    for(i = 0; i < screen_list->count; i++)
403    {
404        destroy_screen(screen_list->screen[i]);
405    }
406
407    if(screen_list->socket_path) {
408        free(screen_list->socket_path);
409    }
410
411    if(screen_list->socket)
412        close(screen_list->socket);
413
414    if(screen_list->screen) free(screen_list->screen);
415
416
417    struct option *option = screen_list->config;
418
419    while(option)
420    {
421        struct option *kromeugnon = option;
422        option = option->next;
423        if(kromeugnon->key)   free(kromeugnon->key);
424        if(kromeugnon->value) free(kromeugnon->value);
425        free(kromeugnon);
426    }
427
428    for(i=0; i<screen_list->recurrent_list->count; i++)
429    {
430        remove_recurrent(screen_list->recurrent_list, i);
431        i = 0;
432    }
433
434    if(screen_list->recurrent_list->recurrent) free(screen_list->recurrent_list->recurrent);
435    if(screen_list->recurrent_list)            free(screen_list->recurrent_list);
436
437    if(screen_list->session_name)
438        free(screen_list->session_name);
439
440    if(screen_list)
441        free(screen_list);
442
443    return mainret;
444}
445
446
447struct screen_list *create_screen_list(void)
448{
449
450    struct screen_list *screen_list = NULL;
451
452    /* Create screen list */
453    screen_list = (struct screen_list*)     malloc(sizeof(struct screen_list));
454    if(!screen_list)
455    {
456        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
457        return NULL;
458    }
459    screen_list->screen = (struct screen**) malloc(sizeof(sizeof(struct screen*)));
460    if(!screen_list->screen)
461    {
462        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
463        free(screen_list);
464        return NULL;
465    }
466
467    screen_list->count = 0;
468    screen_list->mini = 1;
469    screen_list->help = 0;
470    screen_list->status = 1;
471    screen_list->wm_type = WM_VSPLIT;
472    screen_list->in_bell = 0;
473    screen_list->pty = screen_list->prevpty = 0;
474    screen_list->dont_update_coords = 0;
475    screen_list->screensaver_timeout = (60) * 1000000;
476    screen_list->screensaver_data = NULL;
477    screen_list->in_screensaver = 0;
478    screen_list->locked = 0;
479    screen_list->lock_offset = 0;
480    screen_list->attached = 1;
481    screen_list->socket = 0;
482    screen_list->socket_dir    = NULL;
483    screen_list->socket_path   = NULL;
484    screen_list->session_name  = NULL;
485    screen_list->default_shell = NULL;
486
487    screen_list->autolock_timeout = -1;
488
489
490    screen_list->recurrent_list = NULL;
491    screen_list->cv = NULL;
492    screen_list->dp = NULL;
493
494    memset(screen_list->lockmsg, 0, 1024);
495    memset(screen_list->lockpass, 0, 1024);
496
497    return screen_list;
498}
Note: See TracBrowser for help on using the repository browser.