awesomerc.lua: use nano by default if no editor found in env
[awesome.git] / awesome-client.c
blob6e552efaf4cb50734e632e22bdb4024e15953876
1 /*
2 * awesome-client.c - awesome client, communicate with socket
4 * Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
5 * Copyright © 2007 daniel@brinkers.de
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #define _GNU_SOURCE
25 #include <errno.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <sys/socket.h>
29 #include <sys/un.h>
30 #include <fcntl.h>
32 #include <stdio.h>
33 #include <readline/readline.h>
34 #include <readline/history.h>
36 #include "common/socket.h"
37 #include "common/version.h"
38 #include "common/util.h"
40 /* GNU/Hurd workaround */
41 #ifndef MSG_NOSIGNAL
42 #define MSG_NOSIGNAL 0
43 #endif
45 struct sockaddr_un *addr;
46 int csfd;
47 char *display;
49 /** Initialize the client and server socket connections.
50 * If something goes wrong, preserves errno.
51 * \return 0 if everything worked, 1 otherwise.
53 static bool
54 sockets_init(void)
56 if((csfd = socket_getclient()) < 0)
57 return false;
59 if(!(addr = socket_getaddr(display)))
60 return false;
62 if(connect(csfd, addr, sizeof(struct sockaddr_un)) == -1)
63 return false;
65 return true;
68 /** Close the client and server socket connections.
70 static void
71 sockets_close(void)
73 close(csfd);
74 p_delete(&addr);
77 /** Reconnect sockets.
79 static void
80 sockets_reconnect(void)
82 warn("connection lost, reconnecting…");
83 sockets_close();
84 sockets_init();
87 /** Send a message to awesome.
88 * \param msg The message.
89 * \param msg_len The message length.
90 * \return The errno of sendto().
92 static int
93 send_msg(const char *msg, ssize_t msg_len)
95 if(send(csfd, msg, msg_len, MSG_NOSIGNAL | MSG_EOR) == -1)
97 switch (errno)
99 case ENOENT:
100 warn("can't write to %s", addr->sun_path);
101 break;
102 case EPIPE:
103 case ENOTCONN:
104 case ECONNRESET:
105 sockets_reconnect();
106 return send_msg(msg, msg_len);
107 default:
108 warn("error sending packet: %s", strerror(errno));
110 return errno;
113 return EXIT_SUCCESS;
117 /** Recieve a message from awesome.
119 static void
120 recv_msg(void)
122 ssize_t r;
123 char buf[1024];
124 int try = 10;
126 while(try)
128 r = recv(csfd, buf, sizeof(buf) - 1, MSG_TRUNC | MSG_DONTWAIT);
129 if (r < 0)
131 if(errno != EAGAIN)
132 return warn("error recieving from UNIX domain socket: %s", strerror(errno));
133 try--;
135 else
136 break;
137 usleep(100000);
140 if(!try)
141 sockets_reconnect();
142 else if(r > 0)
144 buf[r] = '\0';
145 puts(buf);
150 /** Print help and exit(2) with given exit_code.
151 * \param exit_code The exit code.
152 * \return Never return.
154 static void __attribute__ ((noreturn))
155 exit_help(int exit_code)
157 FILE *outfile = (exit_code == EXIT_SUCCESS) ? stdout : stderr;
158 fprintf(outfile, "Usage: awesome-client [--version|--help]\n"
159 "In normal operation, give no parameters and issue commands "
160 "on standard input.\n");
161 exit(exit_code);
164 /** Main function of awesome-client.
165 * \param argc Number of args.
166 * \param argv Args array.
167 * \return Value returned by send_msg().
170 main(int argc, char **argv)
172 char buf[1024], *msg, *prompt;
173 int ret_value = EXIT_SUCCESS;
174 ssize_t len, msg_len = 1;
176 if(argc == 2)
178 if(!a_strcmp("-v", argv[1]) || !a_strcmp("--version", argv[1]))
179 eprint_version("awesome-client");
180 else if(!a_strcmp("-h", argv[1]) || !a_strcmp("--help", argv[1]))
181 exit_help(EXIT_SUCCESS);
183 else if(argc > 2)
184 exit_help(EXIT_SUCCESS);
186 display = getenv("DISPLAY");
188 if (!sockets_init())
190 warn("can't connect to UNIX domain socket: %s", strerror(errno));
191 return EXIT_FAILURE;
194 if(isatty(STDIN_FILENO))
196 asprintf(&prompt, "awesome@%s%% ", display ? display : "unknown");
197 while((msg = readline(prompt)))
198 if((msg_len = a_strlen(msg)))
200 add_history (msg);
201 p_realloc(&msg, msg_len + 2);
202 msg[msg_len] = '\n';
203 msg[msg_len + 1] = '\0';
204 if(send_msg(msg, msg_len + 2) == EXIT_SUCCESS)
205 recv_msg();
206 p_delete(&msg);
209 else
211 msg = p_new(char, 1);
212 while(fgets(buf, sizeof(buf), stdin))
214 len = a_strlen(buf);
215 if(len < 2 && msg_len > 1)
217 ret_value = send_msg(msg, msg_len);
218 p_delete(&msg);
219 if (ret_value != EXIT_SUCCESS)
220 return ret_value;
221 msg = p_new(char, 1);
222 msg_len = 1;
224 else if (len > 1)
226 msg_len += len;
227 p_realloc(&msg, msg_len);
228 a_strncat(msg, msg_len, buf, len);
231 if(msg_len > 1)
233 if((ret_value = send_msg(msg, msg_len)) == EXIT_SUCCESS)
234 recv_msg();
236 p_delete(&msg);
239 sockets_close();
240 return ret_value;
243 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80