direct-io.hg

view tools/console/client/main.c @ 11424:ae46cac48659

This patch improves error message of xm console command.

# xm console Domain-0
Can't specify Domain-0

Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
author Ewan Mellor <ewan@xensource.com>
date Tue Sep 05 17:06:01 2006 +0100 (2006-09-05)
parents 163c65c47d86
children 5f998c3170f7
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 <pty.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 /* don't worry too much if setting terminal attributes fail */
75 static void init_term(int fd, struct termios *old)
76 {
77 struct termios new_term;
79 if (tcgetattr(fd, old) == -1) {
80 return;
81 }
83 new_term = *old;
84 cfmakeraw(&new_term);
86 tcsetattr(fd, TCSAFLUSH, &new_term);
87 }
89 static void restore_term(int fd, struct termios *old)
90 {
91 tcsetattr(fd, TCSAFLUSH, old);
92 }
94 static int console_loop(int fd)
95 {
96 int ret;
98 do {
99 fd_set fds;
101 FD_ZERO(&fds);
102 FD_SET(STDIN_FILENO, &fds);
103 FD_SET(fd, &fds);
105 ret = select(fd + 1, &fds, NULL, NULL, NULL);
106 if (ret == -1) {
107 if (errno == EINTR || errno == EAGAIN) {
108 continue;
109 }
110 return -1;
111 }
113 if (FD_ISSET(STDIN_FILENO, &fds)) {
114 ssize_t len;
115 char msg[60];
117 len = read(STDIN_FILENO, msg, sizeof(msg));
118 if (len == 1 && msg[0] == ESCAPE_CHARACTER) {
119 return 0;
120 }
122 if (len == 0 || len == -1) {
123 if (len == -1 &&
124 (errno == EINTR || errno == EAGAIN)) {
125 continue;
126 }
127 return -1;
128 }
130 if (!write_sync(fd, msg, len)) {
131 perror("write() failed");
132 return -1;
133 }
134 }
136 if (FD_ISSET(fd, &fds)) {
137 ssize_t len;
138 char msg[512];
140 len = read(fd, msg, sizeof(msg));
141 if (len == 0 || len == -1) {
142 if (len == -1 &&
143 (errno == EINTR || errno == EAGAIN)) {
144 continue;
145 }
146 return -1;
147 }
149 if (!write_sync(STDOUT_FILENO, msg, len)) {
150 perror("write() failed");
151 return -1;
152 }
153 }
154 } while (received_signal == 0);
156 return 0;
157 }
159 int main(int argc, char **argv)
160 {
161 struct termios attr;
162 int domid;
163 char *sopt = "h";
164 int ch;
165 int opt_ind=0;
166 struct option lopt[] = {
167 { "help", 0, 0, 'h' },
168 { 0 },
170 };
171 char *str_pty, *path;
172 int spty;
173 unsigned int len = 0;
174 struct xs_handle *xs;
175 char *end;
176 time_t now;
178 while((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
179 switch(ch) {
180 case 'h':
181 usage(argv[0]);
182 exit(0);
183 break;
184 }
185 }
187 if ((argc - optind) != 1) {
188 fprintf(stderr, "Invalid number of arguments\n");
189 fprintf(stderr, "Try `%s --help' for more information.\n",
190 argv[0]);
191 exit(EINVAL);
192 }
194 domid = strtol(argv[optind], &end, 10);
195 if (end && *end) {
196 fprintf(stderr, "Invalid DOMID `%s'\n", argv[optind]);
197 fprintf(stderr, "Try `%s --help' for more information.\n",
198 argv[0]);
199 exit(EINVAL);
200 }
202 xs = xs_daemon_open();
203 if (xs == NULL) {
204 err(errno, "Could not contact XenStore");
205 }
207 signal(SIGTERM, sighandler);
209 path = xs_get_domain_path(xs, domid);
210 if (path == NULL)
211 err(errno, "xs_get_domain_path()");
212 path = realloc(path, strlen(path) + strlen("/console/tty") + 1);
213 if (path == NULL)
214 err(ENOMEM, "realloc");
215 strcat(path, "/console/tty");
216 str_pty = xs_read(xs, XBT_NULL, path, &len);
218 /* FIXME consoled currently does not assume domain-0 doesn't have a
219 console which is good when we break domain-0 up. To keep us
220 user friendly, we'll bail out here since no data will ever show
221 up on domain-0. */
222 if (domid == 0) {
223 fprintf(stderr, "Can't specify Domain-0\n");
224 exit(EINVAL);
225 }
227 /* Wait a little bit for tty to appear. There is a race
228 condition that occurs after xend creates a domain. This
229 code might be running before consoled has noticed the new
230 domain and setup a pty for it.
232 A xenstore watch would slightly improve responsiveness but
233 a timeout would still be needed since we don't want to
234 block forever if given an invalid domain or worse yet, a
235 domain that someone else has connected to. */
237 now = time(0);
238 while (str_pty == NULL && (now + 5) > time(0)) {
239 struct timeval tv = { 0, 250000 };
240 select(0, NULL, NULL, NULL, &tv); /* pause briefly */
242 str_pty = xs_read(xs, XBT_NULL, path, &len);
243 }
245 if (str_pty == NULL) {
246 err(errno, "Could not read tty from store");
247 }
249 spty = open(str_pty, O_RDWR | O_NOCTTY);
250 if (spty == -1) {
251 err(errno, "Could not open tty `%s'", str_pty);
252 }
253 free(str_pty);
254 free(path);
256 init_term(STDIN_FILENO, &attr);
257 console_loop(spty);
258 restore_term(STDIN_FILENO, &attr);
260 return 0;
261 }