/* * neercs console-based window manager * Copyright (c) 2006 Sam Hocevar * 2008 Jean-Yves Lamoureux * 2008 Pascal Terjan * All Rights Reserved * * $Id: main.c 2591 2008-07-27 08:25:32Z pterjan $ * * This program is free software. It comes without any warranty, to * the extent permitted by applicable law. You can redistribute it * and/or modify it under the terms of the Do What The Fuck You Want * To Public License, Version 2, as published by Sam Hocevar. See * http://sam.zoy.org/wtfpl/COPYING for more details. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #if !defined HAVE_GETOPT_LONG # include "mygetopt.h" #elif defined HAVE_GETOPT_H # include #endif #if defined HAVE_GETOPT_LONG # define mygetopt getopt_long # define myoptind optind # define myoptarg optarg # define myoption option #endif #include #include #include #include "neercs.h" void version(void) { printf("%s\n", PACKAGE_STRING); printf("Copyright (C) 2006, 2008 Sam Hocevar \n"); printf(" Jean-Yves Lamoureux \n\n"); printf("This is free software. You may redistribute copies of it under the\n"); printf("terms of the Do What The Fuck You Want To Public License, Version 2\n"); printf(".\n"); printf("There is NO WARRANTY, to the extent permitted by law.\n"); printf("\n"); printf("For more informations, visit http://libcaca.zoy.org/wiki/neercs\n"); } void usage(int argc, char **argv) { printf("%s\n", PACKAGE_STRING); printf("Usage : %s [command1] [command2] ... [commandN]\n", argv[0]); printf("Example : %s zsh top \n\n", argv[0]); printf("Options :\n"); printf("\t--config\t-c \t\tuse given config file\n"); printf("\t--pid\t\t-P \t\tgrab \n"); printf("\t\t\t-r [session]\t\treattach to a detached neercs\n"); printf("\t\t\t-R [session]\t\treattach if possible, otherwise start a new session\n"); printf("\t\t\t-S \t\tname this session instead of \n"); printf("\t--version\t-v \t\t\tdisplay version and exit\n"); printf("\t--help\t\t-h \t\t\tthis help\n"); } int main(int argc, char **argv) { struct screen_list *screen_list = NULL; struct passwd *user_info; char *user_path = NULL, *user_dir = NULL; int i, args, s=0; long long unsigned int last_key_time = 0; int mainret = -1; int attach = 0, forceattach = 0; int *to_grab = NULL; char **to_start = NULL; int nb_to_grab = 0; screen_list = create_screen_list(); screen_list->default_shell = getenv("SHELL"); args = argc -1; if(screen_list->default_shell == NULL && args <= 0) { fprintf(stderr, "Environment variable SHELL not set and no arguments given. kthxbye.\n"); goto end; } if(args==0) args = 1; /* Build local config file path */ user_dir = getenv("HOME"); if(!user_dir) { user_info = getpwuid(getuid()); if(user_info) { user_dir = user_info->pw_dir; } } if(user_dir) { user_path = malloc(strlen(user_dir) + strlen("/.neercsrc") + 1); sprintf(user_path, "%s/%s", user_dir, ".neercsrc"); } screen_list->recurrent_list = (struct recurrent_list*) malloc(sizeof(struct recurrent_list)); screen_list->recurrent_list->recurrent = (struct recurrent**) malloc(sizeof(struct recurrent*)); if(!screen_list->recurrent_list->recurrent) { fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__); goto end; } screen_list->recurrent_list->count = 0; for(;;) { int option_index = 0; int pidopt; static struct myoption long_options[] = { { "config", 1, NULL, 'c' }, #if defined USE_GRAB { "pid", 1, NULL, 'P' }, #endif { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'v' }, }; #if defined USE_GRAB int c = mygetopt(argc, argv, "c:S:R::r::P:hv", long_options, &option_index); #else int c = mygetopt(argc, argv, "c:S:R::r::hv", long_options, &option_index); #endif if(c == -1) break; switch(c) { case 'c': /* --config */ if(user_path) free(user_path); user_path = strdup(myoptarg); s+=2; break; case 'S': if(!screen_list->session_name) screen_list->session_name = strdup(myoptarg); s+=2; break; case 'P': /* --pid */ pidopt = atoi(myoptarg); if(pidopt <= 0) { fprintf(stderr, "Invalid pid %d\n", pidopt); if(to_grab) free(to_grab); return -1; } if(!to_grab) { /* At most argc-1-s times -P + final 0 */ to_grab = (int *)malloc(((argc-1-s)/2+1)*sizeof(int)); if(!to_grab) { fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__); goto end; } } to_grab[nb_to_grab++] = pidopt; to_grab[nb_to_grab] = 0; s+=2; break; case 'r': forceattach = 1; case 'R': if(attach) { fprintf(stderr, "Attaching can only be requested once\n"); goto end; } if(myoptarg) { if(screen_list->session_name) free(screen_list->session_name); screen_list->session_name = strdup(myoptarg); s+=1; } attach = 1; s+=1; break; case 'h': /* --help */ usage(argc, argv); mainret = 0; goto end; break; case 'v': /* --version */ version(); mainret = 0; goto end; break; default: fprintf(stderr, "Unknown argument #%d\n", myoptind); goto end; break; } } if(s < argc - 1) { to_start = (char**)malloc((argc-s)*sizeof(char*)); if(!to_start) { fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__); goto end; } for(i=0; i<(argc-1) - s; i++) { to_start[i] = strdup(argv[i+s+1]); } to_start[argc-1-s] = NULL; } /* Read global configuration first */ read_configuration_file("/etc/neercsrc", screen_list); /* Then local one */ if(user_path) { read_configuration_file(user_path, screen_list); free(user_path); } if(attach) { char **sockets; if(nb_to_grab || (argc-1 > s)) { fprintf(stderr, "-R can not be associated with commands or pids!\n"); goto end; } sockets = list_sockets(screen_list->socket_dir, screen_list->session_name); if(sockets && sockets[0]) { char *session; for(i=0; sockets[i]; i++); i--; screen_list->s_socket_path = strdup(sockets[i]); session = connect_server(screen_list); if(session) { /* Create main canvas and associated caca window */ screen_list->cv = cucul_create_canvas(0, 0); screen_list->dp = caca_create_display(screen_list->cv); if(!screen_list->dp) goto end; caca_set_cursor(screen_list->dp, 1); screen_list->c_socket_path = build_socket_path(screen_list->socket_dir, session, 1); create_client_socket(screen_list); request_attach(screen_list); if(screen_list->session_name) free(screen_list->session_name); screen_list->session_name = session; } else { fprintf(stderr, "Failed to attach!\n"); free(screen_list->s_socket_path); screen_list->s_socket_path = NULL; attach = 0; } for(i=0; sockets[i]; i++) free(sockets[i]); free(sockets); } else { fprintf(stderr, "No socket found!\n"); attach = 0; } if(forceattach && !attach) goto end; } /* Build default session name */ if(!screen_list->session_name) { char mypid[32]; /* FIXME Compute the length of PID_MAX ? */ snprintf(mypid, 31, "%d", getpid()); mypid[31]= '\0'; screen_list->session_name = strdup(mypid); if(!screen_list->session_name) { fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__); goto end; } } if(!screen_list->c_socket_path) screen_list->c_socket_path = build_socket_path(screen_list->socket_dir, screen_list->session_name, 1); if(!screen_list->s_socket_path) screen_list->s_socket_path = build_socket_path(screen_list->socket_dir, screen_list->session_name, 0); /* Fork the server if needed */ if(!attach) { pid_t pid; pid = fork(); if(pid < 0) { fprintf(stderr, "Failed to create child process\n"); goto end; } if(pid == 0) { int fd; close(0); close(1); close(2); fd = open("/dev/null", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); dup2(fd, 0); #ifndef DEBUG dup2(fd, 1); dup2(fd, 2); if (fd > 2) close(fd); #else if(fd != 0) close(fd); fd = open("/tmp/log.txt", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); dup2(fd, 1); dup2(fd, 2); if (fd > 2) close(fd); #endif setsid(); return server_main(to_grab, to_start, screen_list); } create_client_socket(screen_list); free(connect_server(screen_list)); /* Create main canvas and associated caca window */ screen_list->cv = cucul_create_canvas(0, 0); screen_list->dp = caca_create_display(screen_list->cv); if(!screen_list->dp) goto end; caca_set_cursor(screen_list->dp, 1); request_attach(screen_list); } last_key_time = get_us(); for(;;) { caca_event_t ev; int ret = 0; ssize_t n; char buf[128*1024]; while (screen_list->c_socket && (n = read(screen_list->c_socket, buf, sizeof(buf)-1)) > 0) { buf[n] = 0; debug("Received from server: %s", buf); if(!strncmp("DETACH", buf, 6)) { ret = 1; break; } else if(!strncmp("REFRESH ", buf, 8)) { cucul_import_memory(screen_list->cv, buf+8, n-8, "caca"); caca_refresh_display(screen_list->dp); } else if(!strncmp("CURSOR ", buf, 7)) { caca_set_cursor(screen_list->dp, atoi(buf+7)); } else if(!strncmp("TITLE ", buf, 6)) { caca_set_display_title(screen_list->dp, buf+6); caca_refresh_display(screen_list->dp); } else { debug("Unknown message received from server: %s", buf); } } if(ret) break; ret = caca_get_event(screen_list->dp, CACA_EVENT_ANY, &ev, 100000); if(ret) ret = send_event(ev, screen_list); if(ret) break; } /* Clean up */ mainret = 0; end: if(screen_list) { if(screen_list->dp) caca_free_display(screen_list->dp); if(screen_list->cv) cucul_free_canvas(screen_list->cv); for(i = 0; i < screen_list->count; i++) { destroy_screen(screen_list->screen[i]); } if(screen_list->s_socket_path) free(screen_list->s_socket_path); if(screen_list->c_socket_path) { unlink(screen_list->c_socket_path); free(screen_list->c_socket_path); } if(screen_list->c_socket) close(screen_list->c_socket); if(screen_list->s_socket) close(screen_list->s_socket); if(screen_list->screen) free(screen_list->screen); struct option *option = screen_list->config; while(option) { struct option *kromeugnon = option; option = option->next; if(kromeugnon->key) free(kromeugnon->key); if(kromeugnon->value) free(kromeugnon->value); free(kromeugnon); } for(i=0; irecurrent_list->count; i++) { remove_recurrent(screen_list->recurrent_list, i); i = 0; } if(screen_list->recurrent_list->recurrent) free(screen_list->recurrent_list->recurrent); if(screen_list->recurrent_list) free(screen_list->recurrent_list); if(screen_list->session_name) free(screen_list->session_name); free(screen_list); } return mainret; } struct screen_list *create_screen_list(void) { struct screen_list *screen_list = NULL; /* Create screen list */ screen_list = (struct screen_list*) malloc(sizeof(struct screen_list)); if(!screen_list) { fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__); return NULL; } screen_list->screen = (struct screen**) malloc(sizeof(sizeof(struct screen*))); if(!screen_list->screen) { fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__); free(screen_list); return NULL; } screen_list->count = 0; screen_list->mini = 1; screen_list->help = 0; screen_list->status = 1; screen_list->wm_type = WM_VSPLIT; screen_list->in_bell = 0; screen_list->pty = screen_list->prevpty = 0; screen_list->dont_update_coords = 0; screen_list->screensaver_timeout = (60) * 1000000; screen_list->screensaver_data = NULL; screen_list->in_screensaver = 0; screen_list->locked = 0; screen_list->lock_offset = 0; screen_list->attached = 1; screen_list->s_socket = 0; screen_list->c_socket = 0; screen_list->socket_dir = NULL; screen_list->s_socket_path = NULL; screen_list->c_socket_path = NULL; screen_list->session_name = NULL; screen_list->default_shell = NULL; screen_list->autolock_timeout = -1; screen_list->recurrent_list = NULL; screen_list->cv = NULL; screen_list->dp = NULL; memset(screen_list->lockmsg, 0, 1024); memset(screen_list->lockpass, 0, 1024); return screen_list; }