buffer: use a_strlen()
[awesome.git] / awesome-client.c
bloba70f4f0637aad92a34c02d61a0b36c8c4663ea69
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 #ifndef __FreeBSD__
96 if(send(csfd, msg, msg_len, MSG_NOSIGNAL | MSG_EOR) == -1)
97 #else
98 if(send(csfd, msg, msg_len, MSG_NOSIGNAL | MSG_EOF) == -1)
99 #endif
101 switch (errno)
103 case ENOENT:
104 warn("can't write to %s", addr->sun_path);
105 break;
106 case EPIPE:
107 case ENOTCONN:
108 case ECONNRESET:
109 sockets_reconnect();
110 return send_msg(msg, msg_len);
111 default:
112 warn("error sending packet: %s", strerror(errno));
114 return errno;
117 return EXIT_SUCCESS;
121 /** Recieve a message from awesome.
123 static void
124 recv_msg(void)
126 ssize_t r;
127 char buf[1024];
128 int try = 10;
130 while(try)
132 r = recv(csfd, buf, sizeof(buf) - 1, MSG_TRUNC | MSG_DONTWAIT);
133 if (r < 0)
135 if(errno != EAGAIN)
136 return warn("error recieving from UNIX domain socket: %s", strerror(errno));
137 try--;
139 else
140 break;
141 usleep(100000);
144 if(!try)
145 sockets_reconnect();
146 else if(r > 0)
148 buf[r] = '\0';
149 puts(buf);
154 /** Print help and exit(2) with given exit_code.
155 * \param exit_code The exit code.
156 * \return Never return.
158 static void __attribute__ ((noreturn))
159 exit_help(int exit_code)
161 FILE *outfile = (exit_code == EXIT_SUCCESS) ? stdout : stderr;
162 fprintf(outfile, "Usage: awesome-client [--version|--help]\n"
163 "In normal operation, give no parameters and issue commands "
164 "on standard input.\n");
165 exit(exit_code);
168 /** Main function of awesome-client.
169 * \param argc Number of args.
170 * \param argv Args array.
171 * \return Value returned by send_msg().
174 main(int argc, char **argv)
176 char buf[1024], *msg, *prompt;
177 int ret_value = EXIT_SUCCESS;
178 ssize_t len, msg_len = 1;
180 if(argc == 2)
182 if(!a_strcmp("-v", argv[1]) || !a_strcmp("--version", argv[1]))
183 eprint_version("awesome-client");
184 else if(!a_strcmp("-h", argv[1]) || !a_strcmp("--help", argv[1]))
185 exit_help(EXIT_SUCCESS);
187 else if(argc > 2)
188 exit_help(EXIT_SUCCESS);
190 display = getenv("DISPLAY");
192 if (!sockets_init())
194 warn("can't connect to UNIX domain socket: %s", strerror(errno));
195 return EXIT_FAILURE;
198 if(isatty(STDIN_FILENO))
200 asprintf(&prompt, "awesome@%s%% ", display ? display : "unknown");
201 while((msg = readline(prompt)))
202 if((msg_len = a_strlen(msg)))
204 add_history (msg);
205 p_realloc(&msg, msg_len + 2);
206 msg[msg_len] = '\n';
207 msg[msg_len + 1] = '\0';
208 if(send_msg(msg, msg_len + 2) == EXIT_SUCCESS)
209 recv_msg();
210 p_delete(&msg);
213 else
215 msg = p_new(char, 1);
216 while(fgets(buf, sizeof(buf), stdin))
218 len = a_strlen(buf);
219 if(len < 2 && msg_len > 1)
221 ret_value = send_msg(msg, msg_len);
222 p_delete(&msg);
223 if (ret_value != EXIT_SUCCESS)
224 return ret_value;
225 msg = p_new(char, 1);
226 msg_len = 1;
228 else if (len > 1)
230 msg_len += len;
231 p_realloc(&msg, msg_len);
232 a_strncat(msg, msg_len, buf, len);
235 if(msg_len > 1)
237 if((ret_value = send_msg(msg, msg_len)) == EXIT_SUCCESS)
238 recv_msg();
240 p_delete(&msg);
243 sockets_close();
244 return ret_value;
247 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80