root/src/noit_console.c

Revision 1d69a01311e58ce6ddb007d690b4e9aa4ac08c8c, 6.8 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

And make it all work on OpenBSD (ld -E ? sigh...)

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  */
5
6 #include "noit_defines.h"
7
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <sys/ioctl.h>
12 #ifdef HAVE_TERMIOS_H
13 #include <termios.h>
14 #endif
15 #ifdef HAVE_UTIL_H
16 #include <util.h>
17 #endif
18 #include <arpa/telnet.h>
19
20 #include "eventer/eventer.h"
21 #include "utils/noit_log.h"
22 #include "noit_listener.h"
23 #include "noit_console.h"
24 #include "noit_tokenizer.h"
25
26 int
27 nc_printf(noit_console_closure_t ncct, const char *fmt, ...) {
28   int len;
29   va_list arg;
30   va_start(arg, fmt);
31   len = nc_vprintf(ncct, fmt, arg);
32   va_end(arg);
33   return len;
34 }
35 int
36 nc_vprintf(noit_console_closure_t ncct, const char *fmt, va_list arg) {
37 #ifdef va_copy
38   va_list copy;
39 #endif
40   int lenwanted;
41  
42   if(!ncct->outbuf_allocd) {
43     ncct->outbuf = malloc(4096);
44     if(!ncct->outbuf) return 0;
45     ncct->outbuf_allocd = 4096;
46   }
47   while(1) {
48     char *newbuf;
49 #ifdef va_copy
50     va_copy(copy, arg);
51     lenwanted = vsnprintf(ncct->outbuf + ncct->outbuf_len,
52                           ncct->outbuf_allocd - ncct->outbuf_len,
53                           fmt, copy);
54     va_end(copy);
55 #else
56     lenwanted = vsnprintf(ncct->outbuf + ncct->outbuf_len,
57                           ncct->outbuf_allocd - ncct->outbuf_len,
58                           fmt, arg);
59 #endif
60     if(ncct->outbuf_len + lenwanted < ncct->outbuf_allocd) {
61       /* All went well, things are as we want them. */
62       ncct->outbuf_len += lenwanted;
63       return lenwanted;
64     }
65
66     /* We need to enlarge the buffer */
67     lenwanted += ncct->outbuf_len;
68     lenwanted /= 4096;
69     lenwanted += 1;
70     lenwanted *= 4096;
71     newbuf = realloc(ncct->outbuf, lenwanted);
72     if(!newbuf) {
73       return 0;
74     }
75     ncct->outbuf = newbuf;
76     ncct->outbuf_allocd = lenwanted;
77   }
78   return -1;
79 }
80 int
81 nc_write(noit_console_closure_t ncct, void *buf, int len) {
82   if(!ncct->outbuf_allocd) {
83     ncct->outbuf = malloc(len);
84     if(!ncct->outbuf) return 0;
85     ncct->outbuf_allocd = len;
86   }
87   else if(ncct->outbuf_allocd < ncct->outbuf_len + len) {
88     char *newbuf;
89     newbuf = realloc(ncct->outbuf, ncct->outbuf_len + len);
90     if(!newbuf) return 0;
91     ncct->outbuf = newbuf;
92   }
93   memcpy(ncct->outbuf + ncct->outbuf_len, buf, len);
94   ncct->outbuf_len += len;
95   return len;
96 }
97
98 void
99 noit_console_closure_free(noit_console_closure_t ncct) {
100   if(ncct->el) el_end(ncct->el);
101   if(ncct->hist) history_end(ncct->hist);
102   if(ncct->pty_master >= 0) close(ncct->pty_master);
103   if(ncct->pty_slave >= 0) close(ncct->pty_slave);
104   if(ncct->outbuf) free(ncct->outbuf);
105   if(ncct->telnet) noit_console_telnet_free(ncct->telnet);
106   free(ncct);
107 }
108
109 noit_console_closure_t
110 noit_console_closure_alloc() {
111   noit_console_closure_t new_ncct;
112   new_ncct = calloc(1, sizeof(*new_ncct));
113   new_ncct->pty_master = -1;
114   new_ncct->pty_slave = -1;
115   return new_ncct;
116 }
117
118 int
119 noit_console_continue_sending(noit_console_closure_t ncct,
120                               int *mask) {
121   int len;
122   eventer_t e = ncct->e;
123   if(!ncct->outbuf_len) return 0;
124   while(ncct->outbuf_len > ncct->outbuf_completed) {
125     len = e->opset->write(e->fd, ncct->outbuf + ncct->outbuf_completed,
126                           ncct->outbuf_len - ncct->outbuf_completed,
127                           mask, e);
128     if(len < 0) {
129       if(errno == EAGAIN) return -1;
130       /* Do something else here? */
131       return -1;
132     }
133     ncct->outbuf_completed += len;
134   }
135   len = ncct->outbuf_len;
136   free(ncct->outbuf);
137   ncct->outbuf = NULL;
138   ncct->outbuf_allocd = 0;
139   ncct->outbuf_len = ncct->outbuf_completed = 0;
140   return len;
141 }
142
143 void
144 noit_console_init() {
145   el_multi_init();
146   signal(SIGTTOU, SIG_IGN);
147   eventer_name_callback("noit_console", noit_console_handler);
148 }
149
150 void
151 noit_console_dispatch(eventer_t e, const char *buffer,
152                       noit_console_closure_t ncct) {
153   char *cmds[32];
154   int i, cnt = 32;
155   nc_printf(ncct, "You said: %s\r\n", buffer);
156   i = noit_tokenize(buffer, cmds, &cnt);
157   if(i>cnt) nc_printf(ncct, "Command length too long.\n");
158   if(i<0) nc_printf(ncct, "Error at offset: %d\n", 0-i);
159   for(i=0;i<cnt;i++) {
160     nc_printf(ncct, "[%d] '%s'\r\n", i, cmds[i]);
161     free(cmds[i]);
162   }
163 }
164
165 int
166 noit_console_handler(eventer_t e, int mask, void *closure,
167                      struct timeval *now) {
168   int newmask = EVENTER_READ | EVENTER_EXCEPTION;
169   int keep_going;
170   noit_console_closure_t ncct = closure;
171
172   if(mask & EVENTER_EXCEPTION || (ncct && ncct->wants_shutdown)) {
173 socket_error:
174     /* Exceptions cause us to simply snip the connection */
175     eventer_remove_fd(e->fd);
176     e->opset->close(e->fd, &newmask, e);
177     if(ncct) noit_console_closure_free(ncct);
178     return 0;
179   }
180
181   if(!ncct) {
182     int on = 1;
183     ncct = closure = e->closure = noit_console_closure_alloc();
184     ncct->e = e;
185     if(openpty(&ncct->pty_master, &ncct->pty_slave, NULL, NULL, NULL) ||
186        ioctl(ncct->pty_master, FIONBIO, &on)) {
187       nc_printf(ncct, "Failed to open pty: %s\n", strerror(errno));
188       ncct->wants_shutdown = 1;
189     }
190     else {
191       HistEvent ev;
192       ncct->hist = history_init();
193       history(ncct->hist, &ev, H_SETSIZE, 500);
194       ncct->el = el_init("noitd", ncct->pty_master, e->fd, e->fd);
195       el_set(ncct->el, EL_EDITOR, "emacs");
196       el_set(ncct->el, EL_HIST, history, ncct->hist);
197       ncct->telnet = noit_console_telnet_alloc(ncct);
198     }
199   }
200
201   /* If we still have data to send back to the client, this will take
202    * care of that
203    */
204   if(noit_console_continue_sending(ncct, &newmask) == -1) {
205     if(errno != EAGAIN) goto socket_error;
206     return newmask | EVENTER_EXCEPTION;
207   }
208
209   for(keep_going=1 ; keep_going ; ) {
210     int len, plen;
211     char sbuf[4096];
212     const char *buffer;
213
214     keep_going = 0;
215
216     buffer = el_gets(ncct->el, &plen);
217     if(!el_eagain(ncct->el)) keep_going++;
218
219     len = e->opset->read(e->fd, sbuf, sizeof(sbuf)-1, &newmask, e);
220 noitL(noit_stderr, "opset->read => %d bytes\n", len);
221     if(len == 0 || (len < 0 && errno != EAGAIN)) {
222       eventer_remove_fd(e->fd);
223       close(e->fd);
224       return 0;
225     }
226     if(len > 0) {
227       keep_going++;
228       sbuf[len] = '\0';
229       if(ncct->telnet) {
230         noit_console_telnet_telrcv(ncct, sbuf, len);
231         ptyflush(ncct);
232       }
233       else {
234         write(ncct->pty_slave, sbuf, len);
235       }
236     }
237     if(buffer) {
238       char *cmd_buffer;
239       HistEvent ev;
240       cmd_buffer = malloc(plen+1);
241       memcpy(cmd_buffer, buffer, plen);
242       /* chomp */
243       cmd_buffer[plen] = '\0';
244       if(cmd_buffer[plen-1] == '\n') cmd_buffer[plen-1] = '\0';
245       noitL(noit_debug, "IN: '%s'\n", cmd_buffer);
246       history(ncct->hist, &ev, H_ENTER, cmd_buffer);
247       noit_console_dispatch(e, cmd_buffer, ncct);
248       free(cmd_buffer);
249       if(noit_console_continue_sending(ncct, &newmask) == -1) {
250         if(errno != EAGAIN) goto socket_error;
251         return newmask | EVENTER_EXCEPTION;
252       }
253     }
254   }
255   return newmask | EVENTER_EXCEPTION;
256 }
257
Note: See TracBrowser for help on using the browser.