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