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