A tiling window manager
at hints_fix 231 lines 6.0 kB view raw
1/* 2 * communications.c -- Send commands to a running copy of sdorfehs. 3 * Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts <sabetts@vcn.bc.ca> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the Free 7 * Software Foundation; either version 2 of the License, or (at your option) 8 * any later version. 9 * 10 * This program is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License along with 16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 17 * Place, Suite 330, Boston, MA 02111-1307 USA. 18 */ 19 20#include <X11/X.h> 21#include <X11/Xlib.h> 22#include <X11/Xutil.h> 23#include <X11/Xatom.h> 24#include <X11/Xproto.h> 25 26#include <sys/socket.h> 27#include <sys/un.h> 28#include <fcntl.h> 29#include <string.h> 30#include <unistd.h> 31#include <err.h> 32#include <errno.h> 33#include <stdlib.h> 34 35#include "sdorfehs.h" 36 37#define BUFSZ 1024 38 39void 40init_control_socket_path(void) 41{ 42 char *config_dir; 43 44 config_dir = get_config_dir(); 45 rp_glob_screen.control_socket_path = xsprintf("%s/control", config_dir); 46 free(config_dir); 47} 48 49void 50listen_for_commands(void) 51{ 52 struct sockaddr_un sun; 53 54 if ((rp_glob_screen.control_socket_fd = socket(AF_UNIX, 55 SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) 56 err(1, "socket"); 57 58 if (strlen(rp_glob_screen.control_socket_path) >= sizeof(sun.sun_path)) 59 err(1, "control socket path too long: %s", 60 rp_glob_screen.control_socket_path); 61 62 strncpy(sun.sun_path, rp_glob_screen.control_socket_path, 63 sizeof(sun.sun_path)); 64 sun.sun_family = AF_UNIX; 65 66 if (unlink(rp_glob_screen.control_socket_path) == -1 && 67 errno != ENOENT) 68 err(1, "unlink %s",rp_glob_screen.control_socket_path); 69 70 if (bind(rp_glob_screen.control_socket_fd, (struct sockaddr *)&sun, 71 sizeof(sun)) == -1) 72 err(1, "bind %s", rp_glob_screen.control_socket_path); 73 74 if (chmod(rp_glob_screen.control_socket_path, 0600) == -1) 75 err(1, "chmod %s", rp_glob_screen.control_socket_path); 76 77 if (listen(rp_glob_screen.control_socket_fd, 2) == -1) 78 err(1, "listen %s", rp_glob_screen.control_socket_path); 79 80 PRINT_DEBUG(("listening for commands at %s\n", 81 rp_glob_screen.control_socket_path)); 82} 83 84int 85send_command(int interactive, unsigned char *cmd) 86{ 87 struct sockaddr_un sun; 88 char *wcmd, *bufstart; 89 char ret[BUFSZ+1]; 90 char success = 0; 91 size_t len; 92 ssize_t count; 93 int fd, firstloop; 94 int flags = 0x0; 95 FILE *outf = NULL; 96 97#ifdef SENDCMD_DEBUG 98 pid_t pid = getpid(); 99 char *dpfx = xsprintf("send_command_%d", pid); 100#endif 101 WARNX_DEBUG("%s: enter\n", dpfx); 102 103 len = 1 + strlen((char *)cmd) + 2; 104 wcmd = malloc(len); 105 if (snprintf(wcmd, len, "%c%s\n", interactive, cmd) != (len - 1)) 106 errx(1, "snprintf"); 107 108 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 109 err(1, "socket"); 110 111 if (strlen(rp_glob_screen.control_socket_path) >= sizeof(sun.sun_path)) 112 err(1, "control socket path too long: %s", 113 rp_glob_screen.control_socket_path); 114 115 strncpy(sun.sun_path, rp_glob_screen.control_socket_path, 116 sizeof(sun.sun_path)); 117 sun.sun_family = AF_UNIX; 118 119 if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) 120 err(1, "failed to connect to control socket at %s", 121 rp_glob_screen.control_socket_path); 122 123 if (write(fd, wcmd, len) != len) 124 err(1, "short write to control socket"); 125 126 free(wcmd); 127 128 firstloop = 1; 129 while ((count = recv(fd, &ret, BUFSZ, flags))) { 130 bufstart = ret; 131 if (firstloop) { 132 WARNX_DEBUG("%s: first recv: %zu\n", dpfx, count); 133 /* first byte is exit status */ 134 success = *ret; 135 outf = success ? stdout : stderr; 136 bufstart++; 137 if (count == 2 && *bufstart == '\n') 138 /* commands that had no output */ 139 return success; 140 /* 141 * after blocking for the first buffer, we can keep 142 * reading until it blocks again, which should exhaust 143 * the response. don't want to block when the message 144 * is finished: sometimes connection is closed, other 145 * times it blocks, not sure why? both end a response 146 */ 147 flags += MSG_DONTWAIT; 148 } 149 if (count == -1) { 150 WARNX_DEBUG("%s: finish errno: %d\n", dpfx, errno); 151 if (errno == EAGAIN || errno == ECONNRESET) 152 return success; 153 } 154 ret[count] = '\0'; 155 fprintf(outf, "%s", bufstart); 156 fflush(outf); 157 firstloop = 0; 158 WARNX_DEBUG("%s: looping\n", dpfx); 159 } 160 WARNX_DEBUG("%s: no more bytes\n", dpfx); 161#ifdef SENDCMD_DEBUG 162 free(dpfx); 163#endif 164 165 return success; 166} 167 168void 169receive_command(void) 170{ 171 cmdret *cmd_ret; 172 char cmd[BUFSZ] = { 0 }, c; 173 char *result, *rcmd; 174 int cl, len = 0, interactive = 0; 175 176 PRINT_DEBUG(("have connection waiting on command socket\n")); 177 178 if ((cl = accept(rp_glob_screen.control_socket_fd, NULL, NULL)) == -1) { 179 warn("accept"); 180 return; 181 } 182 183 while (len <= sizeof(cmd)) { 184 if (len == sizeof(cmd)) { 185 warn("%s: bogus command length", __func__); 186 close(cl); 187 return; 188 } 189 190 if (read(cl, &c, 1) == 1) { 191 if (c == '\n') { 192 cmd[len++] = '\0'; 193 break; 194 } 195 cmd[len++] = c; 196 } else if (errno != EAGAIN) { 197 PRINT_DEBUG(("bad read result on control socket: %s\n", 198 strerror(errno))); 199 break; 200 } 201 } 202 203 interactive = cmd[0]; 204 rcmd = cmd + 1; 205 206 PRINT_DEBUG(("read %d byte(s) on command socket: %s\n", len, rcmd)); 207 208 cmd_ret = command(interactive, rcmd); 209 210 /* notify the client of any text that was returned by the command */ 211 len = 2; 212 if (cmd_ret->output) { 213 result = xsprintf("%c%s\n", cmd_ret->success ? 1 : 0, 214 cmd_ret->output); 215 len = 1 + strlen(cmd_ret->output) + 1; 216 } else if (cmd_ret->success) 217 result = xsprintf("%c\n", 1); 218 else 219 result = xsprintf("%c\n", 0); 220 221 cmdret_free(cmd_ret); 222 223 PRINT_DEBUG(("writing back %d to command client: %s", len, result + 1)); 224 225 if (write(cl, result, len) != len) 226 warn("%s: short write", __func__); 227 228 PRINT_DEBUG(("receive_command: write finished, closing\n")); 229 230 close(cl); 231}