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