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, see <http://www.gnu.org/licenses/>.
18 \*/
19
20 #include <getopt.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <signal.h>
27 #include <sys/types.h>
28 #include <sys/resource.h>
29
30 #include "xenctrl.h"
31
32 #include "utils.h"
33 #include "io.h"
34
35 int log_reload = 0;
36 int log_guest = 0;
37 int log_hv = 0;
38 int log_time_hv = 0;
39 int log_time_guest = 0;
40 char *log_dir = NULL;
41 int discard_overflowed_data = 1;
42 int replace_escape = 0;
43
handle_hup(int sig)44 static void handle_hup(int sig)
45 {
46 log_reload = 1;
47 }
48
usage(char * name)49 static void usage(char *name)
50 {
51 printf("Usage: %s [-h] [-V] [-v] [-i] [--log=none|guest|hv|all] [--log-dir=DIR] [--pid-file=PATH] [-t, --timestamp=none|guest|hv|all] [-o, --overflow-data=discard|keep] [--replace-escape]\n", name);
52 printf(" --replace-escape - replace ESC character with dot when writing console log\n");
53 }
54
version(char * name)55 static void version(char *name)
56 {
57 printf("Xen Console Daemon 3.0\n");
58 }
59
increase_fd_limit(void)60 static void increase_fd_limit(void)
61 {
62 /*
63 * We require many file descriptors:
64 * - per domain: pty master, pty slave, logfile and evtchn
65 * - misc extra: hypervisor log, privcmd, gntdev, std...
66 *
67 * Allow a generous 1000 for misc, and calculate the maximum possible
68 * number of fds which could be used.
69 */
70 unsigned min_fds = (DOMID_FIRST_RESERVED * 4) + 1000;
71 struct rlimit lim, new = { min_fds, min_fds };
72
73 if (getrlimit(RLIMIT_NOFILE, &lim) < 0) {
74 fprintf(stderr, "Failed to obtain fd limit: %s\n",
75 strerror(errno));
76 exit(1);
77 }
78
79 /* Do we already have sufficient? Great! */
80 if (lim.rlim_cur >= min_fds)
81 return;
82
83 /* Try to increase our limit. */
84 if (setrlimit(RLIMIT_NOFILE, &new) < 0)
85 syslog(LOG_WARNING,
86 "Unable to increase fd limit from {%llu, %llu} to "
87 "{%llu, %llu}: (%s) - May run out with lots of domains",
88 (unsigned long long)lim.rlim_cur,
89 (unsigned long long)lim.rlim_max,
90 (unsigned long long)new.rlim_cur,
91 (unsigned long long)new.rlim_max,
92 strerror(errno));
93 }
94
main(int argc,char ** argv)95 int main(int argc, char **argv)
96 {
97 const char *sopts = "hVvit:o:";
98 struct option lopts[] = {
99 { "help", 0, 0, 'h' },
100 { "version", 0, 0, 'V' },
101 { "verbose", 0, 0, 'v' },
102 { "interactive", 0, 0, 'i' },
103 { "log", 1, 0, 'l' },
104 { "log-dir", 1, 0, 'r' },
105 { "pid-file", 1, 0, 'p' },
106 { "timestamp", 1, 0, 't' },
107 { "overflow-data", 1, 0, 'o'},
108 { "replace-escape", 0, 0, 'e'},
109 { 0 },
110 };
111 bool is_interactive = false;
112 int ch;
113 int syslog_option = LOG_CONS;
114 int syslog_mask = LOG_MASK(LOG_WARNING)|LOG_MASK(LOG_ERR)|LOG_MASK(LOG_CRIT)|\
115 LOG_MASK(LOG_ALERT)|LOG_MASK(LOG_EMERG);
116 int opt_ind = 0;
117 char *pidfile = NULL;
118
119 while ((ch = getopt_long(argc, argv, sopts, lopts, &opt_ind)) != -1) {
120 switch (ch) {
121 case 'h':
122 usage(argv[0]);
123 exit(0);
124 case 'V':
125 version(argv[0]);
126 exit(0);
127 case 'v':
128 #ifndef __sun__
129 syslog_option |= LOG_PERROR;
130 #endif
131 syslog_mask |= LOG_MASK(LOG_NOTICE)|LOG_MASK(LOG_INFO)| \
132 LOG_MASK(LOG_DEBUG);
133 break;
134 case 'i':
135 is_interactive = true;
136 break;
137 case 'l':
138 if (!strcmp(optarg, "all")) {
139 log_hv = 1;
140 log_guest = 1;
141 } else if (!strcmp(optarg, "hv")) {
142 log_hv = 1;
143 } else if (!strcmp(optarg, "guest")) {
144 log_guest = 1;
145 }
146 break;
147 case 'r':
148 log_dir = strdup(optarg);
149 break;
150 case 'p':
151 pidfile = strdup(optarg);
152 break;
153 case 't':
154 if (!strcmp(optarg, "all")) {
155 log_time_hv = 1;
156 log_time_guest = 1;
157 } else if (!strcmp(optarg, "hv")) {
158 log_time_hv = 1;
159 } else if (!strcmp(optarg, "guest")) {
160 log_time_guest = 1;
161 } else if (!strcmp(optarg, "none")) {
162 log_time_guest = 0;
163 log_time_hv = 0;
164 }
165 break;
166 case 'o':
167 if (!strcmp(optarg, "keep")) {
168 discard_overflowed_data = 0;
169 } else if (!strcmp(optarg, "discard")) {
170 discard_overflowed_data = 1;
171 }
172 break;
173 case 'e':
174 replace_escape = 1;
175 break;
176 case '?':
177 fprintf(stderr,
178 "Try `%s --help' for more information\n",
179 argv[0]);
180 exit(EINVAL);
181 }
182 }
183
184 if (!log_dir) {
185 log_dir = strdup(XEN_LOG_DIR "/console");
186 }
187
188 if (geteuid() != 0) {
189 fprintf(stderr, "%s requires root to run.\n", argv[0]);
190 exit(EPERM);
191 }
192
193 signal(SIGHUP, handle_hup);
194
195 openlog("xenconsoled", syslog_option, LOG_DAEMON);
196 setlogmask(syslog_mask);
197
198 increase_fd_limit();
199
200 if (!is_interactive) {
201 daemonize(pidfile ? pidfile : XEN_RUN_DIR "/xenconsoled.pid");
202 }
203
204 if (!xen_setup())
205 exit(1);
206
207 handle_io();
208
209 closelog();
210 free(log_dir);
211 free(pidfile);
212
213 return 0;
214 }
215
216 /*
217 * Local variables:
218 * mode: C
219 * c-file-style: "linux"
220 * indent-tabs-mode: t
221 * c-basic-offset: 8
222 * tab-width: 8
223 * End:
224 */
225