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

Last change on this file since 3969 was 3969, checked in by Jean-Yves Lamoureux, 11 years ago
  • Massive indentation pass, could insert odd things, blame pterjan, he doesn't care.
  • Property svn:keywords set to Id
File size: 13.8 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 3969 2009-11-19 16:26:53Z 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 <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
56        ("                         Jean-Yves Lamoureux <jylam@lnxscene.org>\n\n");
57    printf
58        ("This is free software.  You may redistribute copies of it under the\n");
59    printf
60        ("terms of the Do What The Fuck You Want To Public License, Version 2\n");
61    printf("<http://sam.zoy.org/wtfpl/>.\n");
62    printf("There is NO WARRANTY, to the extent permitted by law.\n");
63    printf("\n");
64    printf
65        ("For more informations, visit http://libcaca.zoy.org/wiki/neercs\n");
66}
67
68void usage(int argc, char **argv)
69{
70    printf("%s\n", PACKAGE_STRING);
71    printf("Usage : %s [command1] [command2] ... [commandN]\n", argv[0]);
72    printf("Example : %s zsh top \n\n", argv[0]);
73    printf("Options :\n");
74    printf("\t--config\t-c <file>\t\tuse given config file\n");
75    printf("\t--pid\t\t-P [pid]\t\tgrab process\n");
76    printf("\t\t\t-r [session]\t\treattach to a detached neercs\n");
77    printf
78        ("\t\t\t-R [session]\t\treattach if possible, otherwise start a new session\n");
79    printf("\t\t\t-S <name>\t\tname this session <name> instead of <pid>\n");
80    printf("\t--lock-after\t-l [n]\t\t\tlock screen after n seconds\n");
81    printf("\t--version\t-v \t\t\tdisplay version and exit\n");
82    printf("\t--help\t\t-h \t\t\tthis help\n");
83}
84
85int main(int argc, char **argv)
86{
87    struct screen_list *screen_list = NULL;
88    int args;
89
90    int mainret = -1;
91
92    screen_list = create_screen_list();
93    screen_list->default_shell = getenv("SHELL");
94
95    args = argc - 1;
96    if (screen_list->default_shell == NULL && args <= 0)
97    {
98        fprintf(stderr,
99                "Environment variable SHELL not set and no arguments given. kthxbye.\n");
100        goto end;
101    }
102
103    if (handle_command_line(argc, argv, screen_list) < 0)
104        goto end;
105
106    /* Read global configuration first */
107    read_configuration_file("/etc/neercsrc", screen_list);
108
109    /* Then local one */
110    if (screen_list->user_path)
111    {
112        read_configuration_file(screen_list->user_path, screen_list);
113        free(screen_list->user_path);
114    }
115
116    if (screen_list->attach)
117    {
118        if (screen_list->nb_to_grab || screen_list->to_start)
119        {
120            fprintf(stderr,
121                    "-R can not be associated with commands or pids!\n");
122            goto end;
123        }
124
125        attach(screen_list);
126
127        if (screen_list->forceattach && !screen_list->attach)
128            goto end;
129    }
130
131    /* Build default session name */
132    if (!screen_list->session_name)
133    {
134        char mypid[32];         /* FIXME Compute the length of PID_MAX ? */
135        snprintf(mypid, 31, "%d", getpid());
136        mypid[31] = '\0';
137        screen_list->session_name = strdup(mypid);
138        if (!screen_list->session_name)
139        {
140            fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
141                    __LINE__);
142            goto end;
143        }
144    }
145    if (!screen_list->socket_path[SOCK_CLIENT])
146        screen_list->socket_path[SOCK_CLIENT] =
147            build_socket_path(screen_list->socket_dir,
148                              screen_list->session_name, SOCK_CLIENT);
149
150    if (!screen_list->socket_path[SOCK_SERVER])
151        screen_list->socket_path[SOCK_SERVER] =
152            build_socket_path(screen_list->socket_dir,
153                              screen_list->session_name, SOCK_SERVER);
154
155    /* Fork the server if needed */
156    if (!screen_list->attach)
157    {
158        debug("Spawning a new server");
159        if (start_server(screen_list))
160            goto end;
161    }
162
163
164    mainloop(screen_list);
165
166    /* Clean up */
167    mainret = 0;
168  end:
169
170    if (screen_list)
171    {
172        free_screen_list(screen_list);
173    }
174
175    return mainret;
176}
177
178void free_screen_list(struct screen_list *screen_list)
179{
180    int i;
181    struct option *option;
182
183    if (screen_list->dp)
184        caca_free_display(screen_list->dp);
185
186    if (screen_list->cv)
187        caca_free_canvas(screen_list->cv);
188
189    for (i = 0; i < screen_list->count; i++)
190    {
191        destroy_screen(screen_list->screen[i]);
192    }
193
194    if (screen_list->socket_path[SOCK_SERVER])
195        free(screen_list->socket_path[SOCK_SERVER]);
196
197    if (screen_list->socket_path[SOCK_CLIENT])
198    {
199        unlink(screen_list->socket_path[SOCK_CLIENT]);
200        free(screen_list->socket_path[SOCK_CLIENT]);
201    }
202
203    if (screen_list->socket[SOCK_CLIENT])
204        close(screen_list->socket[SOCK_CLIENT]);
205
206    if (screen_list->socket[SOCK_SERVER])
207        close(screen_list->socket[SOCK_SERVER]);
208
209    if (screen_list->screen)
210        free(screen_list->screen);
211
212    option = screen_list->config;
213
214    while (option)
215    {
216        struct option *kromeugnon = option;
217        option = option->next;
218        if (kromeugnon->key)
219            free(kromeugnon->key);
220        if (kromeugnon->value)
221            free(kromeugnon->value);
222        free(kromeugnon);
223    }
224
225    for (i = 0; i < screen_list->recurrent_list->count; i++)
226    {
227        remove_recurrent(screen_list->recurrent_list, i);
228        i = 0;
229    }
230
231    if (screen_list->recurrent_list->recurrent)
232        free(screen_list->recurrent_list->recurrent);
233    if (screen_list->recurrent_list)
234        free(screen_list->recurrent_list);
235
236    if (screen_list->session_name)
237        free(screen_list->session_name);
238
239    if (screen_list->title)
240        free(screen_list->title);
241
242    free(screen_list);
243}
244
245struct screen_list *create_screen_list(void)
246{
247
248    struct screen_list *screen_list = NULL;
249    struct passwd *user_info;
250    char *user_dir = NULL;
251
252    /* Create screen list */
253    screen_list = (struct screen_list *)malloc(sizeof(struct screen_list));
254    if (!screen_list)
255    {
256        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
257                __LINE__);
258        return NULL;
259    }
260    screen_list->screen =
261        (struct screen **)malloc(sizeof(sizeof(struct screen *)));
262    if (!screen_list->screen)
263    {
264        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
265                __LINE__);
266        free(screen_list);
267        return NULL;
268    }
269
270    screen_list->count = 0;
271    screen_list->mini = 1;
272    screen_list->help = 0;
273    screen_list->status = 1;
274    screen_list->title = NULL;
275    screen_list->window_list = 0;
276    screen_list->wm_type = WM_VSPLIT;
277    screen_list->in_bell = 0;
278    screen_list->changed = 0;
279    screen_list->requested_delay = 0;
280    screen_list->delay = 1000 / 60;     /* Don't refresh more than 60 times
281                                           per second */
282    screen_list->pty = screen_list->prevpty = 0;
283    screen_list->dont_update_coords = 0;
284    screen_list->screensaver_timeout = (60) * 1000000;
285    screen_list->screensaver_data = NULL;
286    screen_list->in_screensaver = 0;
287    screen_list->locked = 0;
288    screen_list->lock_offset = 0;
289    screen_list->lock_on_detach = 0;
290    screen_list->attached = 1;
291    screen_list->socket[SOCK_SERVER] = 0;
292    screen_list->socket[SOCK_CLIENT] = 0;
293    screen_list->socket_dir = NULL;
294    screen_list->socket_path[SOCK_SERVER] = NULL;
295    screen_list->socket_path[SOCK_CLIENT] = NULL;
296    screen_list->session_name = NULL;
297    screen_list->default_shell = NULL;
298    screen_list->user_path = NULL;
299    screen_list->autolock_timeout = -1;
300    screen_list->to_grab = NULL;
301    screen_list->to_start = NULL;
302    screen_list->nb_to_grab = 0;
303    screen_list->attach = 0;
304    screen_list->forceattach = 0;
305
306    screen_list->force_refresh = 0;
307    screen_list->cube.in_switch = 0;
308    screen_list->cube.duration = 1000000;
309
310
311    screen_list->recurrent_list = NULL;
312    screen_list->cv = NULL;
313    screen_list->dp = NULL;
314
315    memset(screen_list->lockmsg, 0, 1024);
316    memset(screen_list->lockpass, 0, 1024);
317
318
319
320    /* Build local config file path */
321    user_dir = getenv("HOME");
322    if (!user_dir)
323    {
324        user_info = getpwuid(getuid());
325        if (user_info)
326        {
327            user_dir = user_info->pw_dir;
328        }
329    }
330    if (user_dir)
331    {
332        screen_list->user_path =
333            malloc(strlen(user_dir) + strlen("/.neercsrc") + 1);
334        sprintf(screen_list->user_path, "%s/%s", user_dir, ".neercsrc");
335    }
336
337
338    screen_list->recurrent_list =
339        (struct recurrent_list *)malloc(sizeof(struct recurrent_list));
340    screen_list->recurrent_list->recurrent =
341        (struct recurrent **)malloc(sizeof(struct recurrent *));
342    if (!screen_list->recurrent_list->recurrent)
343    {
344        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
345                __LINE__);
346        free(screen_list);
347        free(screen_list->screen);
348        return NULL;
349    }
350    screen_list->recurrent_list->count = 0;
351
352
353
354    return screen_list;
355}
356
357
358
359int handle_command_line(int argc, char *argv[],
360                        struct screen_list *screen_list)
361{
362    int s = 0, i;
363    for (;;)
364    {
365        int option_index = 0;
366        int pidopt;
367        static struct myoption long_options[] = {
368            {"config", 1, NULL, 'c'},
369#if defined USE_GRAB
370            {"pid", 0, NULL, 'P'},
371#endif
372            {"lock-after", 1, NULL, 'l'},
373            {"help", 0, NULL, 'h'},
374            {"version", 0, NULL, 'v'},
375            {NULL, 0, NULL, 0},
376        };
377#if defined USE_GRAB
378        int c =
379            mygetopt(argc, argv, "c:S:R::l::r::P::hv", long_options,
380                     &option_index);
381#else
382        int c =
383            mygetopt(argc, argv, "c:S:R::l::r::hv", long_options,
384                     &option_index);
385#endif
386        if (c == -1)
387            break;
388
389        switch (c)
390        {
391        case 'c':              /* --config */
392            if (screen_list->user_path)
393                free(screen_list->user_path);
394            screen_list->user_path = strdup(myoptarg);
395            s += 2;
396            break;
397        case 'S':
398            if (!screen_list->session_name)
399                screen_list->session_name = strdup(myoptarg);
400            s += 2;
401            break;
402        case 'P':              /* --pid */
403            if (myoptarg)
404            {
405                pidopt = atoi(myoptarg);
406                if (pidopt <= 0)
407                {
408                    fprintf(stderr, "Invalid pid %d\n", pidopt);
409                    if (screen_list->to_grab)
410                        free(screen_list->to_grab);
411                    return -1;
412                }
413            }
414            else
415                pidopt = select_process(screen_list);
416            if (pidopt <= 0)
417            {
418                s += 1;
419                break;
420            }
421            if (!screen_list->to_grab)
422            {
423                /* At most argc-1-s times -P <pid> + final 0 */
424                screen_list->to_grab =
425                    (int *)malloc(((argc - 1 - s) / 2 + 1) * sizeof(int));
426                if (!screen_list->to_grab)
427                {
428                    fprintf(stderr, "Can't allocate memory at %s:%d\n",
429                            __FUNCTION__, __LINE__);
430                    return -1;
431                }
432            }
433            screen_list->to_grab[screen_list->nb_to_grab++] = pidopt;
434            screen_list->to_grab[screen_list->nb_to_grab] = 0;
435            s += 2;
436            break;
437        case 'l':
438            screen_list->autolock_timeout = atoi(myoptarg) * 1000000;
439            if (screen_list->autolock_timeout == 0)
440                screen_list->autolock_timeout -= 1;
441            break;
442        case 'r':
443            screen_list->forceattach = 1;
444        case 'R':
445            if (screen_list->attach)
446            {
447                fprintf(stderr, "Attaching can only be requested once\n");
448                return -1;
449            }
450            if (myoptarg)
451            {
452                if (screen_list->session_name)
453                    free(screen_list->session_name);
454                screen_list->session_name = strdup(myoptarg);
455                s += 1;
456            }
457            screen_list->attach = 1;
458            s += 1;
459            break;
460        case 'h':              /* --help */
461            usage(argc, argv);
462            return -1;
463            break;
464        case 'v':              /* --version */
465            version();
466            return -1;
467            break;
468        case -2:
469            return -1;
470        default:
471            fprintf(stderr, "Unknown argument #%d\n", myoptind);
472            return -1;
473            break;
474        }
475    }
476    if (s >= 0 && s < argc - 1)
477    {
478        screen_list->to_start = (char **)malloc((argc - s) * sizeof(char *));
479        if (!screen_list->to_start)
480        {
481            fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
482                    __LINE__);
483            return -1;
484        }
485        for (i = 0; i < (argc - 1) - s; i++)
486        {
487            screen_list->to_start[i] = strdup(argv[i + s + 1]);
488        }
489        screen_list->to_start[argc - 1 - s] = NULL;
490    }
491    return s;
492}
Note: See TracBrowser for help on using the repository browser.