/* -*-c-*- */ /* * Fvwm command input interface. * * Copyright 1996, Toshi Isogai. No guarantees or warantees or anything * are provided. Use this program at your own risk. Permission to use * this program for any purpose is given, * as long as the copyright is kept intact. */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* FIXME: The signal handling of this module is largely broken */ #include "config.h" #include "FvwmConsole.h" #include "libs/fio.h" #include "libs/fvwmsignal.h" /* using ParseModuleArgs now */ static ModuleArgs* module; int Fd[2]; /* pipe to fvwm */ int Ns = -1; /* socket handles */ char Name[80]; /* name of this program in executable format */ char *S_name = NULL; /* socket name */ void server(void); RETSIGTYPE DeadPipe(int); void ErrMsg(char *msg); void SigHandler(int); void clean_up(void) { if (Ns != -1) { close(Ns); Ns = -1; } if (S_name != NULL) { unlink(S_name); S_name = NULL; } return; } /* * signal handler */ RETSIGTYPE DeadPipe(int dummy) { clean_up(); exit(0); SIGNAL_RETURN; } RETSIGTYPE SigHandler(int dummy) { clean_up(); exit(0); SIGNAL_RETURN; } RETSIGTYPE ReapChildren(int sig) { fvwmReapChildren(sig); SIGNAL_RETURN; } int main(int argc, char *argv[]) { char client[120]; char **eargv; int i, j, k; char *xterm_pre[] = { "-title", Name, "-name", Name, NULL }; char *xterm_post[] = { "-e", NULL, NULL }; int clpid; /* Why is this not just put in the initializer of xterm_a? * Apparently, it is a non-standard extension to use a non-constant * address (of client) in an initializer (of xterm_a). */ xterm_post[1] = client; module = ParseModuleArgs(argc, argv, 0); /* we don't use an alias */ if (module == NULL) { fprintf( stderr, "FvwmConsole version "VERSION" should only be" " executed by fvwm!\n"); exit(1); } strcpy(Name, module->name); /* construct client's name */ strcpy(client, argv[0]); strcat(client, "C"); eargv =(char **)safemalloc((argc+12)*sizeof(char *)); /* copy arguments */ eargv[0] = XTERM; j = 1; for (k = 0; xterm_pre[k] != NULL; j++, k++) { eargv[j] = xterm_pre[k]; } for (i = 0; i< module->user_argc; i++) { if (!strcmp(module->user_argv[i], "-e")) { i++; break; } else if (!strcmp(module->user_argv[i], "-terminal")) { i++; if (i < module->user_argc) /* use alternative terminal emulator */ eargv[0] = module->user_argv[i]; } else { eargv[j++] = module->user_argv[i]; } } for (k = 0; xterm_post[k] != NULL; j++, k++) { eargv[j] = xterm_post[k]; } /* copy rest of -e args */ for (; iuser_argc; i++, j++) { eargv[j-1] = module->user_argv[i]; } eargv[j] = NULL; signal(SIGCHLD, ReapChildren); /* Dead pipes mean fvwm died */ signal(SIGPIPE, DeadPipe); signal(SIGINT, SigHandler); signal(SIGQUIT, SigHandler); signal(SIGALRM, SigHandler); Fd[0] = module->to_fvwm; Fd[1] = module->from_fvwm; /* launch xterm with client */ clpid = fork(); if (clpid < 0) { ErrMsg("client forking"); } else if (clpid == 0) { execvp(*eargv, eargv); ErrMsg("exec"); } /* tell fvwm we're running */ SendFinishedStartupNotification(Fd); server(); return 0; } /* * setup server and communicate with fvwm and the client */ void server(void) { struct sockaddr_un sas, csas; int len; socklen_t clen; /* length of sockaddr */ char buf[MAX_COMMAND_SIZE]; /* command line buffer */ char *tline; char ver[40]; fd_set fdset; char *home; int s; int msglen; int rc; /* make a socket */ s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0 ) { ErrMsg("socket"); } /* name the socket */ home = getenv("FVWM_USERDIR"); S_name = safemalloc(strlen(home) + sizeof(S_NAME) + 1); strcpy(S_name, home); strcat(S_name, S_NAME); sas.sun_family = AF_UNIX; strcpy(sas.sun_path, S_name); /* bind the above name to the socket: first, erase the old socket */ unlink(S_name); len = sizeof(sas) - sizeof(sas.sun_path) + strlen(sas.sun_path); umask(0077); rc = bind(s, (struct sockaddr *)&sas, len); if (rc < 0) { ErrMsg("bind"); } else { /* don't wait forever for connections */ alarm(FVWMCONSOLE_CONNECTION_TO_SECS); /* listen to the socket */ rc = listen(s, 5); alarm(0); if (rc < 0) { ErrMsg("listen"); } /* accept connections */ clen = sizeof(csas); Ns = accept(s, (struct sockaddr *)&csas, &clen); if (Ns < 0) { ErrMsg("accept"); } } /* send config lines to Client */ tline = NULL; fvwm_send(Ns, C_BEG, strlen(C_BEG), 0); GetConfigLine(Fd, &tline); while (tline != NULL) { if (strlen(tline) > 1) { fvwm_send(Ns, tline, strlen(tline), 0); fvwm_send(Ns, "\n", 1, 0); } GetConfigLine(Fd, &tline); } fvwm_send(Ns, C_END, strlen(C_END), 0); strcpy(ver, "*"); strcpy(ver, module->name); strcat(ver, " version "); strcat(ver, VERSION VERSIONINFO); strcat(ver, "\n"); fvwm_send(Ns, ver, strlen(ver), 0); while (1) { FD_ZERO(&fdset); FD_SET(Ns, &fdset); FD_SET(Fd[1], &fdset); fvwmSelect(FD_SETSIZE, SELECT_FD_SET_CAST &fdset, 0, 0, NULL); if (FD_ISSET(Fd[1], &fdset)) { FvwmPacket* packet = ReadFvwmPacket(Fd[1]); if (packet == NULL) { clean_up(); exit(0); } else { if (packet->type == M_PASS) { msglen = strlen( (char *)&(packet->body[3])); if (msglen > MAX_MESSAGE_SIZE-2) { msglen = MAX_MESSAGE_SIZE-2; } fvwm_send( Ns, (char *)&(packet->body[3]), msglen, 0); } } } if (FD_ISSET(Ns, &fdset)) { int len; int rc; rc = fvwm_recv(Ns, buf, MAX_COMMAND_SIZE, 0); if (rc == 0) { /* client is terminated */ clean_up(); exit(0); } /* process the own unique commands */ len = strlen(buf); if (len > 0 && buf[len - 1] == '\n') { buf[len - 1] = '\0'; } /* send command */ SendText(Fd, buf, 0); } } } /* * print error message on stderr and exit */ void ErrMsg(char *msg) { fprintf( stderr, "%s server error in %s, errno %d: %s\n", Name, msg, errno, strerror(errno)); clean_up(); exit(1); }