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

Last change on this file since 3324 was 3324, checked in by Pascal Terjan, 13 years ago
  • Move attaching logic to a separate function
  • 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 3324 2008-11-14 23:50:48Z 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 <caca.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    int i, args;
83    long long unsigned int last_key_time = 0;
84    int mainret = -1;
85
86
87    screen_list = create_screen_list();
88    screen_list->default_shell = getenv("SHELL");
89
90    args = argc -1;
91    if(screen_list->default_shell == NULL  && args <= 0)
92    {
93        fprintf(stderr, "Environment variable SHELL not set and no arguments given. kthxbye.\n");
94        goto end;
95    }
96
97    if(handle_command_line(argc, argv, screen_list) < 0)
98        goto end;
99
100    /* Read global configuration first */
101    read_configuration_file("/etc/neercsrc", screen_list);
102
103    /* Then local one  */
104    if(screen_list->user_path)
105    {
106        read_configuration_file(screen_list->user_path, screen_list);
107        free(screen_list->user_path);
108    }
109
110    if(screen_list->attach)
111    {
112        if(screen_list->nb_to_grab || screen_list->to_start)
113        {
114            fprintf(stderr, "-R can not be associated with commands or pids!\n");
115            goto end;
116        }
117
118        attach(screen_list);
119
120        if(screen_list->forceattach && !screen_list->attach)
121            goto end;
122    }
123
124    /* Build default session name */
125    if(!screen_list->session_name)
126    {
127        char mypid[32]; /* FIXME Compute the length of PID_MAX ? */
128        snprintf(mypid, 31, "%d", getpid());
129        mypid[31]= '\0';
130        screen_list->session_name = strdup(mypid);
131        if(!screen_list->session_name)
132        {
133            fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
134            goto end;
135        }
136    }
137    if(!screen_list->socket_path[SOCK_CLIENT])
138        screen_list->socket_path[SOCK_CLIENT] =
139            build_socket_path(screen_list->socket_dir, screen_list->session_name, SOCK_CLIENT);
140
141    if(!screen_list->socket_path[SOCK_SERVER])
142        screen_list->socket_path[SOCK_SERVER] =
143            build_socket_path(screen_list->socket_dir, screen_list->session_name, SOCK_SERVER);
144
145    /* Fork the server if needed */
146    if(!screen_list->attach)
147    {
148        if(start_server(screen_list))
149            goto end;
150    }
151
152    last_key_time = get_us();
153
154    for(;;)
155    {
156        caca_event_t ev;
157        int ret = 0;
158        ssize_t n;
159        char buf[128*1024];
160        if(!screen_list) goto end;
161        if (screen_list->socket[SOCK_CLIENT] && (n = read(screen_list->socket[SOCK_CLIENT], buf, sizeof(buf)-1)) > 0)
162        {
163            buf[n] = 0;
164            debug("Received from server: %s", buf);
165            if(!strncmp("DETACH", buf, 6))
166            {
167                ret = 1;
168                break;
169            }
170            else if(!strncmp("REFRESH ", buf, 8))
171            {
172                caca_import_memory(screen_list->cv, buf+8, n-8, "caca");
173                caca_refresh_display(screen_list->dp);
174            }
175            else if(!strncmp("CURSOR ", buf, 7))
176            {
177                caca_set_cursor(screen_list->dp, atoi(buf+7));
178            }
179            else if(!strncmp("TITLE ", buf, 6))
180            {
181                caca_set_display_title(screen_list->dp, buf+6);
182                caca_refresh_display(screen_list->dp);
183            }
184            else
185            {
186                debug("Unknown message received from server: %s", buf);
187            }
188        }
189        if(ret)
190            break;
191
192        ret = caca_get_event(screen_list->dp,
193                             CACA_EVENT_KEY_PRESS
194                             |CACA_EVENT_RESIZE
195                             |CACA_EVENT_QUIT,
196                             &ev, 10000);
197        if(ret)
198            ret = send_event(ev, screen_list);
199
200        if(ret)
201            break;
202    }
203
204    /* Clean up */
205    mainret = 0;
206end:
207    if(screen_list)
208    {
209        if(screen_list->dp)
210            caca_free_display(screen_list->dp);
211
212        if(screen_list->cv)
213            caca_free_canvas(screen_list->cv);
214
215        for(i = 0; i < screen_list->count; i++)
216        {
217            destroy_screen(screen_list->screen[i]);
218        }
219
220        if(screen_list->socket_path[SOCK_SERVER])
221            free(screen_list->socket_path[SOCK_SERVER]);
222
223        if(screen_list->socket_path[SOCK_CLIENT])
224        {
225            unlink(screen_list->socket_path[SOCK_CLIENT]);
226            free(screen_list->socket_path[SOCK_CLIENT]);
227        }
228
229        if(screen_list->socket[SOCK_CLIENT])
230            close(screen_list->socket[SOCK_CLIENT]);
231
232        if(screen_list->socket[SOCK_SERVER])
233            close(screen_list->socket[SOCK_SERVER]);
234
235        if(screen_list->screen)
236            free(screen_list->screen);
237
238        struct option *option = screen_list->config;
239
240        while(option)
241        {
242            struct option *kromeugnon = option;
243            option = option->next;
244            if(kromeugnon->key)   free(kromeugnon->key);
245            if(kromeugnon->value) free(kromeugnon->value);
246            free(kromeugnon);
247        }
248
249        for(i=0; i<screen_list->recurrent_list->count; i++)
250        {
251            remove_recurrent(screen_list->recurrent_list, i);
252            i = 0;
253        }
254
255        if(screen_list->recurrent_list->recurrent)
256            free(screen_list->recurrent_list->recurrent);
257        if(screen_list->recurrent_list)
258            free(screen_list->recurrent_list);
259
260        if(screen_list->session_name)
261            free(screen_list->session_name);
262
263        if(screen_list->title)
264            free(screen_list->title);
265
266        free(screen_list);
267    }
268
269    return mainret;
270}
271
272
273struct screen_list *create_screen_list(void)
274{
275
276    struct screen_list *screen_list = NULL;
277    struct passwd *user_info;
278    char *user_dir = NULL;
279
280    /* Create screen list */
281    screen_list = (struct screen_list*)     malloc(sizeof(struct screen_list));
282    if(!screen_list)
283    {
284        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
285        return NULL;
286    }
287    screen_list->screen = (struct screen**) malloc(sizeof(sizeof(struct screen*)));
288    if(!screen_list->screen)
289    {
290        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
291        free(screen_list);
292        return NULL;
293    }
294
295    screen_list->count = 0;
296    screen_list->mini = 1;
297    screen_list->help = 0;
298    screen_list->status = 1;
299    screen_list->title = NULL;
300    screen_list->window_list = 0;
301    screen_list->wm_type = WM_VSPLIT;
302    screen_list->in_bell = 0;
303    screen_list->pty = screen_list->prevpty = 0;
304    screen_list->dont_update_coords = 0;
305    screen_list->screensaver_timeout = (60) * 1000000;
306    screen_list->screensaver_data = NULL;
307    screen_list->in_screensaver = 0;
308    screen_list->locked = 0;
309    screen_list->lock_offset = 0;
310    screen_list->attached = 1;
311    screen_list->socket[SOCK_SERVER] = 0;
312    screen_list->socket[SOCK_CLIENT] = 0;
313    screen_list->socket_dir    = NULL;
314    screen_list->socket_path[SOCK_SERVER] = NULL;
315    screen_list->socket_path[SOCK_CLIENT] = NULL;
316    screen_list->session_name  = NULL;
317    screen_list->default_shell = NULL;
318    screen_list->user_path     = NULL;
319    screen_list->autolock_timeout = -1;
320    screen_list->to_grab = NULL;
321    screen_list->to_start = NULL;
322    screen_list->nb_to_grab = 0;
323    screen_list->attach = 0;
324    screen_list->forceattach = 0;
325
326
327    screen_list->recurrent_list = NULL;
328    screen_list->cv = NULL;
329    screen_list->dp = NULL;
330
331    memset(screen_list->lockmsg, 0, 1024);
332    memset(screen_list->lockpass, 0, 1024);
333
334
335
336    /* Build local config file path */
337    user_dir = getenv("HOME");
338    if(!user_dir)
339    {
340        user_info = getpwuid(getuid());
341        if(user_info)
342        {
343            user_dir = user_info->pw_dir;
344        }
345    }
346    if(user_dir)
347    {
348        screen_list->user_path = malloc(strlen(user_dir) + strlen("/.neercsrc") + 1);
349        sprintf(screen_list->user_path, "%s/%s", user_dir, ".neercsrc");
350    }
351
352
353    screen_list->recurrent_list = (struct recurrent_list*) malloc(sizeof(struct recurrent_list));
354    screen_list->recurrent_list->recurrent = (struct recurrent**) malloc(sizeof(struct recurrent*));
355    if(!screen_list->recurrent_list->recurrent)
356    {
357        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
358        free(screen_list);
359        free(screen_list->screen);
360        return NULL;
361    }
362    screen_list->recurrent_list->count = 0;
363
364
365
366    return screen_list;
367}
368
369
370
371int handle_command_line(int argc, char *argv[], struct screen_list *screen_list)
372{
373    int s = 0, i;
374    for(;;)
375    {
376        int option_index = 0;
377        int pidopt;
378        static struct myoption long_options[] =
379            {
380                { "config",      1, NULL, 'c' },
381#if defined USE_GRAB
382                { "pid",         1, NULL, 'P' },
383#endif
384                { "help",        0, NULL, 'h' },
385                { "version",     0, NULL, 'v' },
386            };
387#if defined USE_GRAB
388        int c = mygetopt(argc, argv, "c:S:R::r::P:hv", long_options, &option_index);
389#else
390        int c = mygetopt(argc, argv, "c:S:R::r::hv", long_options, &option_index);
391#endif
392        if(c == -1)
393            break;
394
395        switch(c)
396        {
397        case 'c': /* --config */
398            if(screen_list->user_path)
399                free(screen_list->user_path);
400            screen_list->user_path = strdup(myoptarg);
401            s+=2;
402            break;
403        case 'S':
404            if(!screen_list->session_name)
405                screen_list->session_name = strdup(myoptarg);
406            s+=2;
407            break;
408        case 'P': /* --pid */
409            pidopt = atoi(myoptarg);
410            if(pidopt <= 0)
411            {
412                fprintf(stderr, "Invalid pid %d\n", pidopt);
413                if(screen_list->to_grab)
414                    free(screen_list->to_grab);
415                return -1;
416            }
417            if(!screen_list->to_grab)
418            {
419                /* At most argc-1-s times -P <pid> + final 0 */
420                screen_list->to_grab = (int *)malloc(((argc-1-s)/2+1)*sizeof(int));
421                if(!screen_list->to_grab)
422                {
423                    fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
424                    return -1;
425                }
426            }
427            screen_list->to_grab[screen_list->nb_to_grab++] = pidopt;
428            screen_list->to_grab[screen_list->nb_to_grab] = 0;
429            s+=2;
430            break;
431        case 'r':
432            screen_list->forceattach = 1;
433        case 'R':
434            if(screen_list->attach)
435            {
436                fprintf(stderr, "Attaching can only be requested once\n");
437                return -1;
438            }
439            if(myoptarg)
440            {
441                if(screen_list->session_name)
442                    free(screen_list->session_name);
443                screen_list->session_name = strdup(myoptarg);
444                s+=1;
445            }
446            screen_list->attach = 1;
447            s+=1;
448            break;
449        case 'h': /* --help */
450            usage(argc, argv);
451            return -1;
452            break;
453        case 'v': /* --version */
454            version();
455            return -1;
456            break;
457        case -2:
458            return -1;
459        default:
460            fprintf(stderr, "Unknown argument #%d\n", myoptind);
461            return -1;
462            break;
463        }
464    }
465    if(s >= 0 && s < argc - 1)
466    {
467        screen_list->to_start = (char**)malloc((argc-s)*sizeof(char*));
468        if(!screen_list->to_start)
469        {
470            fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
471            return -1;
472        }
473        for(i=0; i<(argc-1) - s; i++)
474        {
475            screen_list->to_start[i] = strdup(argv[i+s+1]);
476        }
477        screen_list->to_start[argc-1-s] = NULL;
478    }
479    return s;
480}
Note: See TracBrowser for help on using the repository browser.