1 /*
2 * Copyright 2009-2017 Citrix Ltd and other contributors
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; version 2.1 only. with the special
7 * exception on linking described in file LICENSE.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 */
14
15 #define _GNU_SOURCE
16
17 #include <fcntl.h>
18 #include <limits.h>
19 #include <stdlib.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include <libxl.h>
25 #include <libxl_utils.h>
26
27 #include "xl.h"
28 #include "xl_utils.h"
29
30 #ifndef O_CLOEXEC
31 #define O_CLOEXEC 0
32 #endif
33
dolog(const char * file,int line,const char * func,const char * fmt,...)34 void dolog(const char *file, int line, const char *func, const char *fmt, ...)
35 {
36 va_list ap;
37 char *s = NULL;
38 int rc;
39
40 va_start(ap, fmt);
41 rc = vasprintf(&s, fmt, ap);
42 va_end(ap);
43 if (rc >= 0)
44 /* we ignore write errors since we have no way to report them;
45 * the alternative would be to abort the whole program */
46 libxl_write_exactly(NULL, logfile, s, rc, NULL, NULL);
47 free(s);
48 }
49
xvasprintf(char ** strp,const char * fmt,va_list ap)50 void xvasprintf(char **strp, const char *fmt, va_list ap)
51 {
52 int r = vasprintf(strp, fmt, ap);
53 if (r == -1) {
54 perror("asprintf failed");
55 exit(EXIT_FAILURE);
56 }
57 }
58
xasprintf(char ** strp,const char * fmt,...)59 void xasprintf(char **strp, const char *fmt, ...)
60 {
61 va_list ap;
62 va_start(ap, fmt);
63 xvasprintf(strp, fmt, ap);
64 va_end(ap);
65 }
66
xmalloc(size_t sz)67 void *xmalloc(size_t sz)
68 {
69 void *r;
70 r = malloc(sz);
71 if (!r) {
72 fprintf(stderr,"xl: Unable to malloc %lu bytes.\n",
73 (unsigned long)sz);
74 exit(-ERROR_FAIL);
75 }
76 return r;
77 }
78
xcalloc(size_t n,size_t sz)79 void *xcalloc(size_t n, size_t sz)
80 {
81 void *r = calloc(n, sz);
82 if (!r) {
83 fprintf(stderr,"xl: Unable to calloc %zu bytes.\n", sz*n);
84 exit(-ERROR_FAIL);
85 }
86 return r;
87 }
88
xrealloc(void * ptr,size_t sz)89 void *xrealloc(void *ptr, size_t sz)
90 {
91 void *r;
92 if (!sz) {
93 free(ptr);
94 return 0;
95 }
96 /* realloc(non-0, 0) has a useless return value;
97 * but xrealloc(anything, 0) is like free
98 */
99 r = realloc(ptr, sz);
100 if (!r) {
101 fprintf(stderr,"xl: Unable to realloc to %lu bytes.\n",
102 (unsigned long)sz);
103 exit(-ERROR_FAIL);
104 }
105 return r;
106 }
107
xstrdup(const char * x)108 char *xstrdup(const char *x)
109 {
110 char *r;
111 r = strdup(x);
112 if (!r) {
113 fprintf(stderr, "xl: Unable to strdup a string of length %zu.\n",
114 strlen(x));
115 exit(-ERROR_FAIL);
116 }
117 return r;
118 }
119
flush_stream(FILE * fh)120 void flush_stream(FILE *fh)
121 {
122 const char *fh_name =
123 fh == stdout ? "stdout" :
124 fh == stderr ? "stderr" :
125 (abort(), (const char*)0);
126
127 if (ferror(fh) || fflush(fh)) {
128 perror(fh_name);
129 exit(EXIT_FAILURE);
130 }
131 }
132
find_domain(const char * p)133 uint32_t find_domain(const char *p)
134 {
135 uint32_t domid;
136 int rc;
137
138 rc = libxl_domain_qualifier_to_domid(ctx, p, &domid);
139 if (rc) {
140 fprintf(stderr, "%s is an invalid domain identifier (rc=%d)\n", p, rc);
141 exit(EXIT_FAILURE);
142 }
143 common_domname = libxl_domid_to_name(ctx, domid);
144 return domid;
145 }
146
147 /*
148 * Callers should use SWITCH_FOREACH_OPT in preference to calling this
149 * directly.
150 */
def_getopt(int argc,char * const argv[],const char * optstring,const struct option * longopts,const char * helpstr,int reqargs)151 int def_getopt(int argc, char * const argv[],
152 const char *optstring,
153 const struct option *longopts,
154 const char* helpstr, int reqargs)
155 {
156 int opt;
157 const struct option def_options[] = {
158 COMMON_LONG_OPTS
159 };
160
161 if (!longopts)
162 longopts = def_options;
163
164 opterr = 0;
165 while ((opt = getopt_long(argc, argv, optstring, longopts, NULL)) == '?') {
166 if (optopt == 'h') {
167 help(helpstr);
168 exit(0);
169 }
170 fprintf(stderr, "option `%c' not supported.\n", optopt);
171 exit(2);
172 }
173 if (opt == 'h') {
174 help(helpstr);
175 exit(0);
176 }
177 if (opt != -1)
178 return opt;
179
180 if (argc - optind <= reqargs - 1) {
181 fprintf(stderr, "'xl %s' requires at least %d argument%s.\n\n",
182 helpstr, reqargs, reqargs > 1 ? "s" : "");
183 help(helpstr);
184 exit(2);
185 }
186 return -1;
187 }
188
string_realloc_append(char ** accumulate,const char * more)189 void string_realloc_append(char **accumulate, const char *more)
190 {
191 /* Appends more to accumulate. Accumulate is either NULL, or
192 * points (always) to a malloc'd nul-terminated string. */
193
194 size_t oldlen = *accumulate ? strlen(*accumulate) : 0;
195 size_t morelen = strlen(more) + 1/*nul*/;
196 if (oldlen > SSIZE_MAX || morelen > SSIZE_MAX - oldlen) {
197 fprintf(stderr,"Additional config data far too large\n");
198 exit(-ERROR_FAIL);
199 }
200
201 *accumulate = xrealloc(*accumulate, oldlen + morelen);
202 memcpy(*accumulate + oldlen, more, morelen);
203 }
204
print_bitmap(uint8_t * map,int maplen,FILE * stream)205 void print_bitmap(uint8_t *map, int maplen, FILE *stream)
206 {
207 int i;
208 uint8_t pmap = 0, bitmask = 0;
209 int firstset = 0, state = 0;
210
211 for (i = 0; i < maplen; i++) {
212 if (i % 8 == 0) {
213 pmap = *map++;
214 bitmask = 1;
215 } else bitmask <<= 1;
216
217 switch (state) {
218 case 0:
219 case 2:
220 if ((pmap & bitmask) != 0) {
221 firstset = i;
222 state++;
223 }
224 continue;
225 case 1:
226 case 3:
227 if ((pmap & bitmask) == 0) {
228 fprintf(stream, "%s%d", state > 1 ? "," : "", firstset);
229 if (i - 1 > firstset)
230 fprintf(stream, "-%d", i - 1);
231 state = 2;
232 }
233 continue;
234 }
235 }
236 switch (state) {
237 case 0:
238 fprintf(stream, "none");
239 break;
240 case 2:
241 break;
242 case 1:
243 if (firstset == 0) {
244 fprintf(stream, "all");
245 break;
246 }
247 case 3:
248 fprintf(stream, "%s%d", state > 1 ? "," : "", firstset);
249 if (i - 1 > firstset)
250 fprintf(stream, "-%d", i - 1);
251 break;
252 }
253 }
254
do_daemonize(const char * name,const char * pidfile)255 int do_daemonize(const char *name, const char *pidfile)
256 {
257 char *fullname;
258 pid_t child1;
259 int nullfd, ret = 0;
260
261 child1 = xl_fork(child_waitdaemon, "domain monitoring daemonizing child");
262 if (child1) {
263 ret = child_report(child_waitdaemon);
264 if (ret) goto out;
265 ret = 1;
266 goto out;
267 }
268
269 postfork();
270
271 ret = libxl_create_logfile(ctx, name, &fullname);
272 if (ret) {
273 LOG("failed to open logfile %s: %s",fullname,strerror(errno));
274 exit(-1);
275 }
276
277 CHK_SYSCALL(logfile = open(fullname, O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC, 0644));
278 free(fullname);
279 assert(logfile >= 3);
280
281 CHK_SYSCALL(nullfd = open("/dev/null", O_RDONLY));
282 assert(nullfd >= 3);
283
284 dup2(nullfd, 0);
285 dup2(logfile, 1);
286 dup2(logfile, 2);
287
288 close(nullfd);
289
290 CHK_SYSCALL(daemon(0, 1));
291
292 if (pidfile) {
293 int fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR|S_IWUSR);
294 char *pid = NULL;
295
296 if (fd == -1) {
297 perror("Unable to open pidfile");
298 exit(1);
299 }
300
301 if (asprintf(&pid, "%ld\n", (long)getpid()) == -1) {
302 perror("Formatting pid");
303 exit(1);
304 }
305
306 if (write(fd, pid, strlen(pid)) < 0) {
307 perror("Writing pid");
308 exit(1);
309 }
310
311 if (close(fd) < 0) {
312 perror("Closing pidfile");
313 exit(1);
314 }
315
316 free(pid);
317 }
318
319 out:
320 return ret;
321 }
322
323 /*
324 * Local variables:
325 * mode: C
326 * c-basic-offset: 4
327 * indent-tabs-mode: nil
328 * End:
329 */
330