debuggers.hg

view tools/console/client/main.c @ 20956:5e49312fcb44

tools/xenconsole: fix Segmentation fault

Segmentation fault occurs if DOMID isn't specified.
Some check be added to output error message in this situation.

Signed-off-by: Yu Zhiguo <yuzg@cn.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Feb 08 08:50:03 2010 +0000 (2010-02-08)
parents 74911141ce79
children 3ffdb094c2c0
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>
38 #ifdef __sun__
39 #include <sys/stropts.h>
40 #endif
42 #include "xs.h"
44 #define ESCAPE_CHARACTER 0x1d
46 static volatile sig_atomic_t received_signal = 0;
48 static void sighandler(int signum)
49 {
50 received_signal = 1;
51 }
53 static bool write_sync(int fd, const void *data, size_t size)
54 {
55 size_t offset = 0;
56 ssize_t len;
58 while (offset < size) {
59 len = write(fd, data + offset, size - offset);
60 if (len < 1) {
61 return false;
62 }
63 offset += len;
64 }
66 return true;
67 }
69 static void usage(const char *program) {
70 printf("Usage: %s [OPTION] DOMID\n"
71 "Attaches to a virtual domain console\n"
72 "\n"
73 " -h, --help display this help and exit\n"
74 " -n, --num N use console number N\n"
75 , program);
76 }
78 #ifdef __sun__
79 void cfmakeraw(struct termios *termios_p)
80 {
81 termios_p->c_iflag &=
82 ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
83 termios_p->c_oflag &= ~OPOST;
84 termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
85 termios_p->c_cflag &= ~(CSIZE|PARENB);
86 termios_p->c_cflag |= CS8;
88 termios_p->c_cc[VMIN] = 0;
89 termios_p->c_cc[VTIME] = 0;
90 }
91 #endif
93 static int get_pty_fd(struct xs_handle *xs, char *path, int seconds)
94 /* Check for a pty in xenstore, open it and return its fd.
95 * Assumes there is already a watch set in the store for this path. */
96 {
97 struct timeval tv;
98 fd_set watch_fdset;
99 int xs_fd = xs_fileno(xs), pty_fd = -1;
100 int start, now;
101 unsigned int len = 0;
102 char *pty_path, **watch_paths;
104 start = now = time(NULL);
105 do {
106 tv.tv_usec = 0;
107 tv.tv_sec = (start + seconds) - now;
108 FD_ZERO(&watch_fdset);
109 FD_SET(xs_fd, &watch_fdset);
110 if (select(xs_fd + 1, &watch_fdset, NULL, NULL, &tv)) {
111 /* Read the watch to drain the buffer */
112 watch_paths = xs_read_watch(xs, &len);
113 free(watch_paths);
114 /* We only watch for one thing, so no need to
115 * disambiguate: just read the pty path */
116 pty_path = xs_read(xs, XBT_NULL, path, &len);
117 if (pty_path != NULL) {
118 pty_fd = open(pty_path, O_RDWR | O_NOCTTY);
119 if (pty_fd == -1)
120 err(errno, "Could not open tty `%s'",
121 pty_path);
122 free(pty_path);
123 }
124 }
125 } while (pty_fd == -1 && (now = time(NULL)) < start + seconds);
127 #ifdef __sun__
128 if (pty_fd != -1) {
129 struct termios term;
131 /*
132 * The pty may come from either xend (with pygrub) or
133 * xenconsoled. It may have tty semantics set up, or not.
134 * While it isn't strictly necessary to have those
135 * semantics here, it is good to have a consistent
136 * state that is the same as under Linux.
137 *
138 * If tcgetattr fails, they have not been set up,
139 * so go ahead and set them up now, by pushing the
140 * ptem and ldterm streams modules.
141 */
142 if (tcgetattr(pty_fd, &term) < 0) {
143 ioctl(pty_fd, I_PUSH, "ptem");
144 ioctl(pty_fd, I_PUSH, "ldterm");
145 }
146 }
147 #endif
149 return pty_fd;
150 }
153 /* don't worry too much if setting terminal attributes fail */
154 static void init_term(int fd, struct termios *old)
155 {
156 struct termios new_term;
158 if (tcgetattr(fd, old) == -1)
159 return;
161 new_term = *old;
162 cfmakeraw(&new_term);
164 tcsetattr(fd, TCSANOW, &new_term);
165 }
167 static void restore_term(int fd, struct termios *old)
168 {
169 tcsetattr(fd, TCSANOW, old);
170 }
172 static int console_loop(int fd, struct xs_handle *xs, char *pty_path)
173 {
174 int ret, xs_fd = xs_fileno(xs), max_fd;
176 do {
177 fd_set fds;
179 FD_ZERO(&fds);
180 FD_SET(STDIN_FILENO, &fds);
181 max_fd = STDIN_FILENO;
182 FD_SET(xs_fd, &fds);
183 if (xs_fd > max_fd) max_fd = xs_fd;
184 if (fd != -1) FD_SET(fd, &fds);
185 if (fd > max_fd) max_fd = fd;
187 ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
188 if (ret == -1) {
189 if (errno == EINTR || errno == EAGAIN) {
190 continue;
191 }
192 return -1;
193 }
195 if (FD_ISSET(xs_fileno(xs), &fds)) {
196 int newfd = get_pty_fd(xs, pty_path, 0);
197 if (fd != -1)
198 close(fd);
199 if (newfd == -1)
200 /* Console PTY has become invalid */
201 return 0;
202 fd = newfd;
203 continue;
204 }
206 if (FD_ISSET(STDIN_FILENO, &fds)) {
207 ssize_t len;
208 char msg[60];
210 len = read(STDIN_FILENO, msg, sizeof(msg));
211 if (len == 1 && msg[0] == ESCAPE_CHARACTER) {
212 return 0;
213 }
215 if (len == 0 || len == -1) {
216 if (len == -1 &&
217 (errno == EINTR || errno == EAGAIN)) {
218 continue;
219 }
220 return -1;
221 }
223 if (!write_sync(fd, msg, len)) {
224 close(fd);
225 fd = -1;
226 continue;
227 }
228 }
230 if (fd != -1 && FD_ISSET(fd, &fds)) {
231 ssize_t len;
232 char msg[512];
234 len = read(fd, msg, sizeof(msg));
235 if (len == 0 || len == -1) {
236 if (len == -1 &&
237 (errno == EINTR || errno == EAGAIN)) {
238 continue;
239 }
240 close(fd);
241 fd = -1;
242 continue;
243 }
245 if (!write_sync(STDOUT_FILENO, msg, len)) {
246 perror("write() failed");
247 return -1;
248 }
249 }
250 } while (received_signal == 0);
252 return 0;
253 }
255 int main(int argc, char **argv)
256 {
257 struct termios attr;
258 int domid;
259 char *sopt = "hn:";
260 int ch;
261 unsigned int num = 0;
262 int opt_ind=0;
263 struct option lopt[] = {
264 { "num", 1, 0, 'n' },
265 { "help", 0, 0, 'h' },
266 { 0 },
268 };
269 char *dom_path = NULL, *path = NULL;
270 int spty, xsfd;
271 struct xs_handle *xs;
272 char *end;
274 while((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
275 switch(ch) {
276 case 'h':
277 usage(argv[0]);
278 exit(0);
279 break;
280 case 'n':
281 num = atoi(optarg);
282 break;
283 default:
284 fprintf(stderr, "Invalid argument\n");
285 fprintf(stderr, "Try `%s --help' for more information.\n",
286 argv[0]);
287 exit(EINVAL);
288 }
289 }
291 if (optind >= argc) {
292 fprintf(stderr, "DOMID should be specified\n");
293 fprintf(stderr, "Try `%s --help' for more information.\n",
294 argv[0]);
295 exit(EINVAL);
296 }
297 domid = strtol(argv[optind], &end, 10);
298 if (end && *end) {
299 fprintf(stderr, "Invalid DOMID `%s'\n", argv[optind]);
300 fprintf(stderr, "Try `%s --help' for more information.\n",
301 argv[0]);
302 exit(EINVAL);
303 }
305 xs = xs_daemon_open();
306 if (xs == NULL) {
307 err(errno, "Could not contact XenStore");
308 }
310 signal(SIGTERM, sighandler);
312 dom_path = xs_get_domain_path(xs, domid);
313 if (dom_path == NULL)
314 err(errno, "xs_get_domain_path()");
315 path = malloc(strlen(dom_path) + strlen("/serial/0/tty") + 5);
316 if (path == NULL)
317 err(ENOMEM, "malloc");
318 snprintf(path, strlen(dom_path) + strlen("/serial/0/tty") + 5, "%s/serial/%d/tty", dom_path, num);
320 /* FIXME consoled currently does not assume domain-0 doesn't have a
321 console which is good when we break domain-0 up. To keep us
322 user friendly, we'll bail out here since no data will ever show
323 up on domain-0. */
324 if (domid == 0) {
325 fprintf(stderr, "Can't specify Domain-0\n");
326 exit(EINVAL);
327 }
329 /* Set a watch on this domain's console pty */
330 if (!xs_watch(xs, path, ""))
331 err(errno, "Can't set watch for console pty");
332 xsfd = xs_fileno(xs);
334 /* Wait a little bit for tty to appear. There is a race
335 condition that occurs after xend creates a domain. This code
336 might be running before consoled has noticed the new domain
337 and setup a pty for it. */
338 spty = get_pty_fd(xs, path, 5);
339 if (spty == -1) {
340 err(errno, "Could not read tty from store");
341 }
343 init_term(spty, &attr);
344 init_term(STDIN_FILENO, &attr);
345 console_loop(spty, xs, path);
346 restore_term(STDIN_FILENO, &attr);
348 free(path);
349 free(dom_path);
350 return 0;
351 }