Leverage configure checks && use select
[freeradius.git] / src / main / radmin.c
1 /*
2  * radmin.c     RADIUS Administration tool.
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2008   The FreeRADIUS server project
21  * Copyright 2008   Alan DeKok <aland@deployingradius.com>
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include <freeradius-devel/libradius.h>
28 #include <freeradius-devel/radpaths.h>
29
30 #ifdef HAVE_READLINE_READLINE_H
31 #include <readline/readline.h>
32 #include <readline/history.h>
33 #endif
34
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
37 #endif
38
39 #ifdef HAVE_SYS_UN_H
40 #include <sys/un.h>
41 #endif
42
43
44 static int fr_domain_socket(const char *path)
45 {
46         int sockfd;
47         size_t len;
48         socklen_t socklen;
49         struct sockaddr_un saremote;
50
51         len = strlen(path);
52         if (len >= sizeof(saremote.sun_path)) {
53                 fprintf(stderr, "Path too long in filename\n");
54                 return -1;
55         }
56
57         if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
58                 fprintf(stderr, "Failed creating socket: %s\n",
59                         strerror(errno));
60                 return -1;
61         }
62
63         saremote.sun_family = AF_UNIX;
64         memcpy(saremote.sun_path, path, len); /* not zero terminated */
65         
66         socklen = sizeof(saremote.sun_family) + len;
67
68         if (connect(sockfd, (struct sockaddr *)&saremote, socklen) < 0) {
69                 fprintf(stderr, "Failed connecting to %s: %s\n",
70                         path, strerror(errno));
71                 close(sockfd);
72                 return -1;
73         }
74
75 #ifdef O_NONBLOCK
76         {
77                 int flags;
78                 
79                 if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0)  {
80                         fprintf(stderr, "Failure getting socket flags: %s",
81                                 strerror(errno));
82                         close(sockfd);
83                         return -1;
84                 }
85                 
86                 flags |= O_NONBLOCK;
87                 if( fcntl(sockfd, F_SETFL, flags) < 0) {
88                         fprintf(stderr, "Failure setting socket flags: %s",
89                                 strerror(errno));
90                         close(sockfd);
91                         return -1;
92                 }
93         }
94 #endif
95
96         return sockfd;
97 }
98
99 int main(int argc, char **argv)
100 {
101         int sockfd, port;
102         char *line;
103         ssize_t len, size;
104         const char *file = RUNDIR "/radiusd/radiusd.sock";
105         char *p, buffer[2048];
106
107         if ((argc > 2) ||
108             ((argc == 2) && (strcmp(argv[1], "-h") == 0))) {
109                 printf("Usage: radmin [socket]\n");
110                 exit(0);
111         }
112
113         if (argc == 2) file = argv[1];
114
115 #ifdef HAVE_READLINE_READLINE_H
116         using_history();
117         rl_bind_key('\t', rl_insert);
118 #endif
119
120         /*
121          *      FIXME: Get destination from command line, if possible?
122          */
123         sockfd = fr_domain_socket(file);
124         if (sockfd < 0) {
125                 exit(1);
126         }
127
128         /*
129          *      FIXME: Do login?
130          */
131
132         while (1) {
133 #ifndef HAVE_READLINE_READLINE_H
134                 fprintf(stdout, "radmin> ");
135                 fflush(stdout);
136
137                 line = fgets(buffer, sizeof(buffer), stdin);
138                 if (!line) break;
139
140                 p = strchr(buffer, '\n');
141                 if (!p) {
142                         fprintf(stderr, "line too long\n");
143                         exit(1);
144                 }
145
146                 *p = '\0';
147 #else
148                 line = readline("radmin> ");
149
150                 if (!line) break;
151                 
152                 if (!*line) {
153                         free(line);
154                         continue;
155                 }
156
157                 add_history(line);
158 #endif
159
160                 /*
161                  *      Write the text to the socket.
162                  */
163                 if (write(sockfd, line, strlen(line)) < 0) break;
164                 if (write(sockfd, "\r\n", 2) < 0) break;
165
166                 /*
167                  *      Exit, done, etc.
168                  */
169                 if ((strcmp(line, "exit") == 0) ||
170                     (strcmp(line, "quit") == 0)) {
171                         break;
172                 }
173
174                 /*
175                  *      Read the response
176                  */
177                 size = 0;
178                 buffer[0] = '\0';
179
180                 port = 1;
181                 memset(buffer, 0, sizeof(buffer));
182
183                 while (port == 1) {
184                         int rcode;
185                         fd_set readfds;
186
187                         FD_ZERO(&readfds);
188                         FD_SET(sockfd, &readfds);
189
190                         rcode = select(sockfd + 1, &readfds, NULL, NULL, NULL);
191                         if (rcode < 0) {
192                                 if (errno == EINTR) continue;
193
194                                 fprintf(stderr, "Failed selecting: %s\n",
195                                         strerror(errno));
196                                 exit(1);
197                         }
198
199                         len = recv(sockfd, buffer + size,
200                                    sizeof(buffer) - size - 1, MSG_DONTWAIT);
201                         if (len < 0) {
202                                 /*
203                                  *      No data: keep looping
204                                  */
205                                 if ((errno == EAGAIN) || (errno == EINTR)) {
206                                         continue;
207                                 }
208
209                                 fprintf(stderr, "Error reading socket: %s\n",
210                                         strerror(errno));
211                                 exit(1);
212                         }
213                         if (len == 0) break; /* clean close of socket */
214
215                         size += len;
216                         buffer[size] = '\0';
217
218                         /*
219                          *      There really has to be a better way of
220                          *      doing this.
221                          */
222                         p = strstr(buffer, "radmin> ");
223                         if (p &&
224                             ((p == buffer) || 
225                              (p[-1] == '\n') ||
226                              (p[-1] == '\r'))) {
227                                 *p = '\0';
228
229                                 if (p[-1] == '\n') p[-1] = '\0';
230
231                                 port = 0;
232                                 break;
233                         }
234                 }
235
236                 /*
237                  *      Blank prompt.  Go get another line.
238                  */
239                 if (!buffer[0]) continue;
240
241                 buffer[size] = '\0'; /* this is at least right */
242                 puts(buffer);
243                 fflush(stdout);
244         }
245
246         printf("\n");
247
248         return 0;
249 }
250