debuggers.hg

view tools/console/client/main.c @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children dec845b4d9c3
line source
1 /*\
2 * Copyright (C) International Business Machines Corp., 2005
3 * Author(s): Anthony Liguori <aliguori@us.ibm.com>
4 *
5 * Xen Console Daemon
6 *
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; under version 2 of the License.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 \*/
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <time.h>
29 #include <fcntl.h>
30 #include <sys/wait.h>
31 #include <termios.h>
32 #include <signal.h>
33 #include <getopt.h>
34 #include <sys/select.h>
35 #include <err.h>
36 #include <errno.h>
37 #include <string.h>
39 #include "xs.h"
41 #define ESCAPE_CHARACTER 0x1d
43 static volatile sig_atomic_t received_signal = 0;
45 static void sighandler(int signum)
46 {
47 received_signal = 1;
48 }
50 static bool write_sync(int fd, const void *data, size_t size)
51 {
52 size_t offset = 0;
53 ssize_t len;
55 while (offset < size) {
56 len = write(fd, data + offset, size - offset);
57 if (len < 1) {
58 return false;
59 }
60 offset += len;
61 }
63 return true;
64 }
66 static void usage(const char *program) {
67 printf("Usage: %s [OPTION] DOMID\n"
68 "Attaches to a virtual domain console\n"
69 "\n"
70 " -h, --help display this help and exit\n"
71 , program);
72 }
74 static int get_pty_fd(struct xs_handle *xs, char *path, int seconds)
75 /* Check for a pty in xenstore, open it and return its fd.
76 * Assumes there is already a watch set in the store for this path. */
77 {
78 struct timeval tv;
79 fd_set watch_fdset;
80 int xs_fd = xs_fileno(xs), pty_fd = -1;
81 int start, now;
82 unsigned int len = 0;
83 char *pty_path, **watch_paths;;
85 start = now = time(NULL);
86 do {
87 tv.tv_usec = 0;
88 tv.tv_sec = (start + seconds) - now;
89 FD_ZERO(&watch_fdset);
90 FD_SET(xs_fd, &watch_fdset);
91 if (select(xs_fd + 1, &watch_fdset, NULL, NULL, &tv)) {
92 /* Read the watch to drain the buffer */
93 watch_paths = xs_read_watch(xs, &len);
94 free(watch_paths);
95 /* We only watch for one thing, so no need to
96 * disambiguate: just read the pty path */
97 pty_path = xs_read(xs, XBT_NULL, path, &len);
98 if (pty_path != NULL) {
99 pty_fd = open(pty_path, O_RDWR | O_NOCTTY);
100 if (pty_fd == -1)
101 err(errno, "Could not open tty `%s'",
102 pty_path);
103 free(pty_path);
104 }
105 }
106 } while (pty_fd == -1 && (now = time(NULL)) < start + seconds);
107 return pty_fd;
108 }
111 /* don't worry too much if setting terminal attributes fail */
112 static void init_term(int fd, struct termios *old)
113 {
114 struct termios new_term;
116 if (tcgetattr(fd, old) == -1)
117 return;
119 new_term = *old;
120 cfmakeraw(&new_term);
122 tcsetattr(fd, TCSAFLUSH, &new_term);
123 }
125 static void restore_term(int fd, struct termios *old)
126 {
127 tcsetattr(fd, TCSAFLUSH, old);
128 }
130 static int console_loop(int fd, struct xs_handle *xs, char *pty_path)
131 {
132 int ret, xs_fd = xs_fileno(xs), max_fd;
134 do {
135 fd_set fds;
137 FD_ZERO(&fds);
138 FD_SET(STDIN_FILENO, &fds);
139 max_fd = STDIN_FILENO;
140 FD_SET(xs_fd, &fds);
141 if (xs_fd > max_fd) max_fd = xs_fd;
142 if (fd != -1) FD_SET(fd, &fds);
143 if (fd > max_fd) max_fd = fd;
145 ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
146 if (ret == -1) {
147 if (errno == EINTR || errno == EAGAIN) {
148 continue;
149 }
150 return -1;
151 }
153 if (FD_ISSET(xs_fileno(xs), &fds)) {
154 int newfd = get_pty_fd(xs, pty_path, 0);
155 close(fd);
156 if (newfd == -1)
157 /* Console PTY has become invalid */
158 return 0;
159 fd = newfd;
160 continue;
161 }
163 if (FD_ISSET(STDIN_FILENO, &fds)) {
164 ssize_t len;
165 char msg[60];
167 len = read(STDIN_FILENO, msg, sizeof(msg));
168 if (len == 1 && msg[0] == ESCAPE_CHARACTER) {
169 return 0;
170 }
172 if (len == 0 || len == -1) {
173 if (len == -1 &&
174 (errno == EINTR || errno == EAGAIN)) {
175 continue;
176 }
177 return -1;
178 }
180 if (!write_sync(fd, msg, len)) {
181 close(fd);
182 fd = -1;
183 continue;
184 }
185 }
187 if (fd != -1 && FD_ISSET(fd, &fds)) {
188 ssize_t len;
189 char msg[512];
191 len = read(fd, msg, sizeof(msg));
192 if (len == 0 || len == -1) {
193 if (len == -1 &&
194 (errno == EINTR || errno == EAGAIN)) {
195 continue;
196 }
197 close(fd);
198 fd = -1;
199 continue;
200 }
202 if (!write_sync(STDOUT_FILENO, msg, len)) {
203 perror("write() failed");
204 return -1;
205 }
206 }
207 } while (received_signal == 0);
209 return 0;
210 }
212 int main(int argc, char **argv)
213 {
214 struct termios attr;
215 int domid;
216 char *sopt = "h";
217 int ch;
218 int opt_ind=0;
219 struct option lopt[] = {
220 { "help", 0, 0, 'h' },
221 { 0 },
223 };
224 char *path;
225 int spty, xsfd;
226 struct xs_handle *xs;
227 char *end;
229 while((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
230 switch(ch) {
231 case 'h':
232 usage(argv[0]);
233 exit(0);
234 break;
235 }
236 }
238 if ((argc - optind) != 1) {
239 fprintf(stderr, "Invalid number of arguments\n");
240 fprintf(stderr, "Try `%s --help' for more information.\n",
241 argv[0]);
242 exit(EINVAL);
243 }
245 domid = strtol(argv[optind], &end, 10);
246 if (end && *end) {
247 fprintf(stderr, "Invalid DOMID `%s'\n", argv[optind]);
248 fprintf(stderr, "Try `%s --help' for more information.\n",
249 argv[0]);
250 exit(EINVAL);
251 }
253 xs = xs_daemon_open();
254 if (xs == NULL) {
255 err(errno, "Could not contact XenStore");
256 }
258 signal(SIGTERM, sighandler);
260 path = xs_get_domain_path(xs, domid);
261 if (path == NULL)
262 err(errno, "xs_get_domain_path()");
263 path = realloc(path, strlen(path) + strlen("/console/tty") + 1);
264 if (path == NULL)
265 err(ENOMEM, "realloc");
266 strcat(path, "/console/tty");
268 /* FIXME consoled currently does not assume domain-0 doesn't have a
269 console which is good when we break domain-0 up. To keep us
270 user friendly, we'll bail out here since no data will ever show
271 up on domain-0. */
272 if (domid == 0) {
273 fprintf(stderr, "Can't specify Domain-0\n");
274 exit(EINVAL);
275 }
277 /* Set a watch on this domain's console pty */
278 if (!xs_watch(xs, path, ""))
279 err(errno, "Can't set watch for console pty");
280 xsfd = xs_fileno(xs);
282 /* Wait a little bit for tty to appear. There is a race
283 condition that occurs after xend creates a domain. This code
284 might be running before consoled has noticed the new domain
285 and setup a pty for it. */
286 spty = get_pty_fd(xs, path, 5);
287 if (spty == -1) {
288 err(errno, "Could not read tty from store");
289 }
291 init_term(spty, &attr);
292 init_term(STDIN_FILENO, &attr);
293 console_loop(spty, xs, path);
294 restore_term(STDIN_FILENO, &attr);
296 free(path);
297 return 0;
298 }