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