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

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