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 #include <fcntl.h>
16 #include <inttypes.h>
17 #include <limits.h>
18 #include <stdlib.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <sys/utsname.h>
22 #include <time.h>
23 #include <unistd.h>
24 
25 #include <libxl.h>
26 #include <libxl_utils.h>
27 #include <libxlutil.h>
28 
29 #include "xl.h"
30 #include "xl_utils.h"
31 #include "xl_parse.h"
32 
33 static int fd_lock = -1;
34 
35 #ifndef LIBXL_HAVE_NO_SUSPEND_RESUME
suspend_domain(uint32_t domid)36 static void suspend_domain(uint32_t domid)
37 {
38     libxl_domain_suspend_only(ctx, domid, NULL);
39 }
40 
resume_domain(uint32_t domid)41 static void resume_domain(uint32_t domid)
42 {
43     libxl_domain_resume(ctx, domid, 1, NULL);
44 }
45 
main_suspend(int argc,char ** argv)46 int main_suspend(int argc, char **argv)
47 {
48     int opt;
49 
50     SWITCH_FOREACH_OPT(opt, "", NULL, "suspend", 1) {
51         /* No options */
52     }
53 
54     suspend_domain(find_domain(argv[optind]));
55 
56     return EXIT_SUCCESS;
57 }
58 
main_resume(int argc,char ** argv)59 int main_resume(int argc, char **argv)
60 {
61     int opt;
62 
63     SWITCH_FOREACH_OPT(opt, "", NULL, "resume", 1) {
64         /* No options */
65     }
66 
67     resume_domain(find_domain(argv[optind]));
68 
69     return EXIT_SUCCESS;
70 }
71 #endif
72 
pause_domain(uint32_t domid)73 static void pause_domain(uint32_t domid)
74 {
75     libxl_domain_pause(ctx, domid, NULL);
76 }
77 
unpause_domain(uint32_t domid)78 static void unpause_domain(uint32_t domid)
79 {
80     libxl_domain_unpause(ctx, domid, NULL);
81 }
82 
destroy_domain(uint32_t domid,int force)83 static void destroy_domain(uint32_t domid, int force)
84 {
85     int rc;
86 
87     if (domid == 0 && !force) {
88         fprintf(stderr, "Not destroying domain 0; use -f to force.\n"
89                         "This can only be done when using a disaggregated "
90                         "hardware domain and toolstack.\n\n");
91         exit(EXIT_FAILURE);
92     }
93     rc = libxl_domain_destroy(ctx, domid, 0);
94     if (rc) { fprintf(stderr,"destroy failed (rc=%d)\n",rc); exit(EXIT_FAILURE); }
95 }
96 
main_pause(int argc,char ** argv)97 int main_pause(int argc, char **argv)
98 {
99     int opt;
100 
101     SWITCH_FOREACH_OPT(opt, "", NULL, "pause", 1) {
102         /* No options */
103     }
104 
105     pause_domain(find_domain(argv[optind]));
106 
107     return EXIT_SUCCESS;
108 }
109 
main_unpause(int argc,char ** argv)110 int main_unpause(int argc, char **argv)
111 {
112     int opt;
113 
114     SWITCH_FOREACH_OPT(opt, "", NULL, "unpause", 1) {
115         /* No options */
116     }
117 
118     unpause_domain(find_domain(argv[optind]));
119 
120     return EXIT_SUCCESS;
121 }
122 
main_destroy(int argc,char ** argv)123 int main_destroy(int argc, char **argv)
124 {
125     int opt;
126     int force = 0;
127 
128     SWITCH_FOREACH_OPT(opt, "f", NULL, "destroy", 1) {
129     case 'f':
130         force = 1;
131         break;
132     }
133 
134     destroy_domain(find_domain(argv[optind]), force);
135     return EXIT_SUCCESS;
136 }
137 
reboot_domain(uint32_t domid,libxl_evgen_domain_death ** deathw,libxl_ev_user for_user,int fallback_trigger)138 static void reboot_domain(uint32_t domid, libxl_evgen_domain_death **deathw,
139                           libxl_ev_user for_user, int fallback_trigger)
140 {
141     int rc;
142 
143     fprintf(stderr, "Rebooting domain %u\n", domid);
144     rc = libxl_domain_reboot(ctx, domid, NULL);
145     if (rc == ERROR_NOPARAVIRT) {
146         if (fallback_trigger) {
147             fprintf(stderr, "PV control interface not available:"
148                     " sending ACPI reset button event.\n");
149             rc = libxl_send_trigger(ctx, domid, LIBXL_TRIGGER_RESET, 0, NULL);
150         } else {
151             fprintf(stderr, "PV control interface not available:"
152                     " external graceful reboot not possible.\n");
153             fprintf(stderr, "Use \"-F\" to fallback to ACPI reset event.\n");
154         }
155     }
156     if (rc) {
157         fprintf(stderr,"reboot failed (rc=%d)\n",rc);exit(EXIT_FAILURE);
158     }
159 
160     if (deathw) {
161         rc = libxl_evenable_domain_death(ctx, domid, for_user, deathw);
162         if (rc) {
163             fprintf(stderr,"wait for death failed (evgen, rc=%d)\n",rc);
164             exit(EXIT_FAILURE);
165         }
166     }
167 }
168 
shutdown_domain(uint32_t domid,libxl_evgen_domain_death ** deathw,libxl_ev_user for_user,int fallback_trigger)169 static void shutdown_domain(uint32_t domid,
170                             libxl_evgen_domain_death **deathw,
171                             libxl_ev_user for_user,
172                             int fallback_trigger)
173 {
174     int rc;
175 
176     fprintf(stderr, "Shutting down domain %u\n", domid);
177     rc = libxl_domain_shutdown(ctx, domid, NULL);
178     if (rc == ERROR_NOPARAVIRT) {
179         if (fallback_trigger) {
180             fprintf(stderr, "PV control interface not available:"
181                     " sending ACPI power button event.\n");
182             rc = libxl_send_trigger(ctx, domid, LIBXL_TRIGGER_POWER, 0, NULL);
183         } else {
184             fprintf(stderr, "PV control interface not available:"
185                     " external graceful shutdown not possible.\n");
186             fprintf(stderr, "Use \"-F\" to fallback to ACPI power event.\n");
187         }
188     }
189 
190     if (rc) {
191         fprintf(stderr,"shutdown failed (rc=%d)\n",rc);exit(EXIT_FAILURE);
192     }
193 
194     if (deathw) {
195         rc = libxl_evenable_domain_death(ctx, domid, for_user, deathw);
196         if (rc) {
197             fprintf(stderr,"wait for death failed (evgen, rc=%d)\n",rc);
198             exit(EXIT_FAILURE);
199         }
200     }
201 }
202 
wait_for_domain_deaths(libxl_evgen_domain_death ** deathws,int nr,int wait_for_shutdown_or_death)203 static void wait_for_domain_deaths(libxl_evgen_domain_death **deathws, int nr,
204                                    int wait_for_shutdown_or_death)
205 {
206     int rc, count = 0;
207     LOG("Waiting for %d domains", nr);
208     while(1 && count < nr) {
209         libxl_event *event;
210         rc = libxl_event_wait(ctx, &event, LIBXL_EVENTMASK_ALL, 0,0);
211         if (rc) {
212             LOG("Failed to get event, quitting (rc=%d)", rc);
213             exit(EXIT_FAILURE);
214         }
215 
216         switch (event->type) {
217         case LIBXL_EVENT_TYPE_DOMAIN_DEATH:
218             LOG("Domain %d has been destroyed", event->domid);
219             libxl_evdisable_domain_death(ctx, deathws[event->for_user]);
220             count++;
221             break;
222         case LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN:
223             LOG("Domain %d has been shut down, reason code %d",
224                 event->domid, event->u.domain_shutdown.shutdown_reason);
225             if (wait_for_shutdown_or_death) {
226                 libxl_evdisable_domain_death(ctx, deathws[event->for_user]);
227                 count++;
228             } else {
229                 LOG("Domain %d continue waiting for death", event->domid);
230             }
231             break;
232         default:
233             LOG("Unexpected event type %d", event->type);
234             break;
235         }
236         libxl_event_free(ctx, event);
237     }
238 }
239 
main_shutdown_or_reboot(int do_reboot,int argc,char ** argv)240 static int main_shutdown_or_reboot(int do_reboot, int argc, char **argv)
241 {
242     const char *what = do_reboot ? "reboot" : "shutdown";
243     void (*fn)(uint32_t domid,
244                libxl_evgen_domain_death **, libxl_ev_user, int) =
245         do_reboot ? &reboot_domain : &shutdown_domain;
246     int opt, i, nb_domain;
247     int wait_for_it = 0, all = 0, nrdeathws = 0;
248     int fallback_trigger = 0;
249     static struct option opts[] = {
250         {"all", 0, 0, 'a'},
251         {"wait", 0, 0, 'w'},
252         COMMON_LONG_OPTS
253     };
254 
255     SWITCH_FOREACH_OPT(opt, "awF", opts, what, 0) {
256     case 'a':
257         all = 1;
258         break;
259     case 'w':
260         wait_for_it++;
261         break;
262     case 'F':
263         fallback_trigger = 1;
264         break;
265     }
266 
267     if (!argv[optind] && !all) {
268         fprintf(stderr, "You must specify -a or a domain id.\n\n");
269         return EXIT_FAILURE;
270     }
271 
272     if (all) {
273         libxl_dominfo *dominfo;
274         libxl_evgen_domain_death **deathws = NULL;
275         if (!(dominfo = libxl_list_domain(ctx, &nb_domain))) {
276             fprintf(stderr, "libxl_list_domain failed.\n");
277             return EXIT_FAILURE;
278         }
279 
280         if (wait_for_it)
281             deathws = calloc(nb_domain, sizeof(*deathws));
282 
283         for (i = 0; i<nb_domain; i++) {
284             if (dominfo[i].domid == 0 || dominfo[i].never_stop)
285                 continue;
286             fn(dominfo[i].domid, deathws ? &deathws[i] : NULL, i,
287                fallback_trigger);
288             nrdeathws++;
289         }
290 
291         if (deathws) {
292             wait_for_domain_deaths(deathws, nrdeathws, wait_for_it == 1);
293             free(deathws);
294         }
295 
296         libxl_dominfo_list_free(dominfo, nb_domain);
297     } else {
298         libxl_evgen_domain_death *deathw = NULL;
299         uint32_t domid = find_domain(argv[optind]);
300 
301         fn(domid, wait_for_it ? &deathw : NULL, 0, fallback_trigger);
302 
303         if (wait_for_it)
304             wait_for_domain_deaths(&deathw, 1, wait_for_it == 1);
305     }
306 
307 
308     return EXIT_SUCCESS;
309 }
310 
main_shutdown(int argc,char ** argv)311 int main_shutdown(int argc, char **argv)
312 {
313     return main_shutdown_or_reboot(0, argc, argv);
314 }
315 
main_reboot(int argc,char ** argv)316 int main_reboot(int argc, char **argv)
317 {
318     return main_shutdown_or_reboot(1, argc, argv);
319 }
320 
evdisable_disk_ejects(libxl_evgen_disk_eject ** diskws,int num_disks)321 static void evdisable_disk_ejects(libxl_evgen_disk_eject **diskws,
322                                  int num_disks)
323 {
324     int i;
325 
326     for (i = 0; i < num_disks; i++) {
327         if (diskws[i])
328             libxl_evdisable_disk_eject(ctx, diskws[i]);
329         diskws[i] = NULL;
330     }
331 }
332 
domain_wait_event(uint32_t domid,libxl_event ** event_r)333 static int domain_wait_event(uint32_t domid, libxl_event **event_r)
334 {
335     int ret;
336     for (;;) {
337         ret = libxl_event_wait(ctx, event_r, LIBXL_EVENTMASK_ALL, 0,0);
338         if (ret) {
339             LOG("Domain %u, failed to get event, quitting (rc=%d)", domid, ret);
340             return ret;
341         }
342         if ((*event_r)->domid != domid) {
343             char *evstr = libxl_event_to_json(ctx, *event_r);
344             LOG("INTERNAL PROBLEM - ignoring unexpected event for"
345                 " domain %d (expected %d): event=%s",
346                 (*event_r)->domid, domid, evstr);
347             free(evstr);
348             libxl_event_free(ctx, *event_r);
349             continue;
350         }
351         return ret;
352     }
353 }
354 
355 /*
356  * Returns false if memory can't be freed, but also if we encounter errors.
357  * Returns true in case there is already, or we manage to free it, enough
358  * memory, but also if autoballoon is false.
359  */
freemem(uint32_t domid,libxl_domain_config * d_config)360 static bool freemem(uint32_t domid, libxl_domain_config *d_config)
361 {
362     int rc;
363     double credit = 30;
364     uint64_t need_memkb, free_memkb;
365 
366     if (!autoballoon)
367         return true;
368 
369     rc = libxl_domain_need_memory(ctx, d_config, domid, &need_memkb);
370     if (rc < 0)
371         return false;
372 
373     for (;;) {
374         time_t start;
375 
376         rc = libxl_get_free_memory(ctx, &free_memkb);
377         if (rc < 0)
378             return false;
379 
380         if (free_memkb >= need_memkb)
381             return true;
382 
383         if (credit <= 0)
384             return false;
385 
386         rc = libxl_set_memory_target(ctx, 0, free_memkb - need_memkb, 1, 0);
387         if (rc < 0)
388             return false;
389 
390         /* wait until dom0 reaches its target, as long as we are making
391          * progress */
392         start = time(NULL);
393         rc = libxl_wait_for_memory_target(ctx, 0, 10);
394         if (rc < 0)
395             return false;
396 
397         credit -= difftime(time(NULL), start);
398     }
399 }
400 
reload_domain_config(uint32_t domid,libxl_domain_config * d_config)401 static void reload_domain_config(uint32_t domid,
402                                  libxl_domain_config *d_config)
403 {
404     int rc;
405     uint8_t *t_data;
406     int ret, t_len;
407     libxl_domain_config d_config_new;
408 
409     /* In case user has used "config-update" to store a new config
410      * file.
411      */
412     ret = libxl_userdata_retrieve(ctx, domid, "xl", &t_data, &t_len);
413     if (ret && errno != ENOENT) {
414         LOG("\"xl\" configuration found but failed to load\n");
415     }
416     if (t_len > 0) {
417         LOG("\"xl\" configuration found, using it\n");
418         libxl_domain_config_dispose(d_config);
419         libxl_domain_config_init(d_config);
420         parse_config_data("<updated>", (const char *)t_data,
421                           t_len, d_config);
422         free(t_data);
423         libxl_userdata_unlink(ctx, domid, "xl");
424         return;
425     }
426 
427     libxl_domain_config_init(&d_config_new);
428     rc = libxl_retrieve_domain_configuration(ctx, domid, &d_config_new,
429                                              NULL);
430     if (rc) {
431         LOG("failed to retrieve guest configuration (rc=%d). "
432             "reusing old configuration", rc);
433         libxl_domain_config_dispose(&d_config_new);
434     } else {
435         libxl_domain_config_dispose(d_config);
436         /* Steal allocations */
437         memcpy(d_config, &d_config_new, sizeof(libxl_domain_config));
438     }
439 }
440 
441 /* Can update r_domid if domain is destroyed */
handle_domain_death(uint32_t * r_domid,libxl_event * event,libxl_domain_config * d_config)442 static domain_restart_type handle_domain_death(uint32_t *r_domid,
443                                                libxl_event *event,
444                                                libxl_domain_config *d_config)
445 {
446     domain_restart_type restart = DOMAIN_RESTART_NONE;
447     libxl_action_on_shutdown action;
448 
449     switch (event->u.domain_shutdown.shutdown_reason) {
450     case LIBXL_SHUTDOWN_REASON_POWEROFF:
451         action = d_config->on_poweroff;
452         break;
453     case LIBXL_SHUTDOWN_REASON_REBOOT:
454         action = d_config->on_reboot;
455         break;
456     case LIBXL_SHUTDOWN_REASON_SUSPEND:
457         LOG("Domain has suspended.");
458         return DOMAIN_RESTART_SUSPENDED;
459     case LIBXL_SHUTDOWN_REASON_CRASH:
460         action = d_config->on_crash;
461         break;
462     case LIBXL_SHUTDOWN_REASON_WATCHDOG:
463         action = d_config->on_watchdog;
464         break;
465     case LIBXL_SHUTDOWN_REASON_SOFT_RESET:
466         action = d_config->on_soft_reset;
467         break;
468     default:
469         LOG("Unknown shutdown reason code %d. Destroying domain.",
470             event->u.domain_shutdown.shutdown_reason);
471         action = LIBXL_ACTION_ON_SHUTDOWN_DESTROY;
472     }
473 
474     LOG("Action for shutdown reason code %d is %s",
475         event->u.domain_shutdown.shutdown_reason,
476         get_action_on_shutdown_name(action));
477 
478     if (action == LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_DESTROY || action == LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_RESTART) {
479         char *corefile;
480         int rc;
481 
482         xasprintf(&corefile, XEN_DUMP_DIR "/%s", d_config->c_info.name);
483         LOG("dumping core to %s", corefile);
484         rc = libxl_domain_core_dump(ctx, *r_domid, corefile, NULL);
485         if (rc) LOG("core dump failed (rc=%d).", rc);
486         free(corefile);
487         /* No point crying over spilled milk, continue on failure. */
488 
489         if (action == LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_DESTROY)
490             action = LIBXL_ACTION_ON_SHUTDOWN_DESTROY;
491         else
492             action = LIBXL_ACTION_ON_SHUTDOWN_RESTART;
493     }
494 
495     switch (action) {
496     case LIBXL_ACTION_ON_SHUTDOWN_PRESERVE:
497         break;
498 
499     case LIBXL_ACTION_ON_SHUTDOWN_RESTART_RENAME:
500         reload_domain_config(*r_domid, d_config);
501         restart = DOMAIN_RESTART_RENAME;
502         break;
503 
504     case LIBXL_ACTION_ON_SHUTDOWN_RESTART:
505         reload_domain_config(*r_domid, d_config);
506         restart = DOMAIN_RESTART_NORMAL;
507         /* fall-through */
508     case LIBXL_ACTION_ON_SHUTDOWN_DESTROY:
509         LOG("Domain %d needs to be cleaned up: destroying the domain",
510             *r_domid);
511         libxl_domain_destroy(ctx, *r_domid, 0);
512         *r_domid = INVALID_DOMID;
513         break;
514 
515     case LIBXL_ACTION_ON_SHUTDOWN_SOFT_RESET:
516         reload_domain_config(*r_domid, d_config);
517         restart = DOMAIN_RESTART_SOFT_RESET;
518         break;
519 
520     case LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_DESTROY:
521     case LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_RESTART:
522         /* Already handled these above. */
523         abort();
524     }
525 
526     return restart;
527 }
528 
529 /* Preserve a copy of a domain under a new name. Updates *r_domid */
preserve_domain(uint32_t * r_domid,libxl_event * event,libxl_domain_config * d_config)530 static int preserve_domain(uint32_t *r_domid, libxl_event *event,
531                            libxl_domain_config *d_config)
532 {
533     time_t now;
534     struct tm tm;
535     char strtime[24];
536 
537     libxl_uuid new_uuid;
538 
539     int rc;
540 
541     now = time(NULL);
542     if (now == ((time_t) -1)) {
543         LOG("Failed to get current time for domain rename");
544         return 0;
545     }
546 
547     tzset();
548     if (gmtime_r(&now, &tm) == NULL) {
549         LOG("Failed to convert time to UTC");
550         return 0;
551     }
552 
553     if (!strftime(&strtime[0], sizeof(strtime), "-%Y%m%dT%H%MZ", &tm)) {
554         LOG("Failed to format time as a string");
555         return 0;
556     }
557 
558     libxl_uuid_generate(&new_uuid);
559 
560     LOG("Preserving domain %u %s with suffix%s",
561         *r_domid, d_config->c_info.name, strtime);
562     rc = libxl_domain_preserve(ctx, *r_domid, &d_config->c_info,
563                                strtime, new_uuid);
564 
565     /*
566      * Although the domain still exists it is no longer the one we are
567      * concerned with.
568      */
569     *r_domid = INVALID_DOMID;
570 
571     return rc == 0 ? 1 : 0;
572 }
573 
console_child_report(xlchildnum child)574 static void console_child_report(xlchildnum child)
575 {
576     if (xl_child_pid(child))
577         child_report(child);
578 }
579 
vncviewer(uint32_t domid,int autopass)580 static int vncviewer(uint32_t domid, int autopass)
581 {
582     libxl_vncviewer_exec(ctx, domid, autopass);
583     fprintf(stderr, "Unable to execute vncviewer\n");
584     return 1;
585 }
586 
autoconnect_vncviewer(uint32_t domid,int autopass)587 static void autoconnect_vncviewer(uint32_t domid, int autopass)
588 {
589    console_child_report(child_vncviewer);
590 
591     pid_t pid = xl_fork(child_vncviewer, "vncviewer child");
592     if (pid)
593         return;
594 
595     postfork();
596 
597     sleep(1);
598     vncviewer(domid, autopass);
599     _exit(EXIT_FAILURE);
600 }
601 
acquire_lock(void)602 static int acquire_lock(void)
603 {
604     int rc;
605     struct flock fl;
606 
607     /* lock already acquired */
608     if (fd_lock >= 0)
609         return ERROR_INVAL;
610 
611     fl.l_type = F_WRLCK;
612     fl.l_whence = SEEK_SET;
613     fl.l_start = 0;
614     fl.l_len = 0;
615     fd_lock = open(lockfile, O_WRONLY|O_CREAT, S_IWUSR);
616     if (fd_lock < 0) {
617         fprintf(stderr, "cannot open the lockfile %s errno=%d\n", lockfile, errno);
618         return ERROR_FAIL;
619     }
620     if (fcntl(fd_lock, F_SETFD, FD_CLOEXEC) < 0) {
621         close(fd_lock);
622         fprintf(stderr, "cannot set cloexec to lockfile %s errno=%d\n", lockfile, errno);
623         return ERROR_FAIL;
624     }
625 get_lock:
626     rc = fcntl(fd_lock, F_SETLKW, &fl);
627     if (rc < 0 && errno == EINTR)
628         goto get_lock;
629     if (rc < 0) {
630         fprintf(stderr, "cannot acquire lock %s errno=%d\n", lockfile, errno);
631         rc = ERROR_FAIL;
632     } else
633         rc = 0;
634     return rc;
635 }
636 
release_lock(void)637 static int release_lock(void)
638 {
639     int rc;
640     struct flock fl;
641 
642     /* lock not acquired */
643     if (fd_lock < 0)
644         return ERROR_INVAL;
645 
646 release_lock:
647     fl.l_type = F_UNLCK;
648     fl.l_whence = SEEK_SET;
649     fl.l_start = 0;
650     fl.l_len = 0;
651 
652     rc = fcntl(fd_lock, F_SETLKW, &fl);
653     if (rc < 0 && errno == EINTR)
654         goto release_lock;
655     if (rc < 0) {
656         fprintf(stderr, "cannot release lock %s, errno=%d\n", lockfile, errno);
657         rc = ERROR_FAIL;
658     } else
659         rc = 0;
660     close(fd_lock);
661     fd_lock = -1;
662 
663     return rc;
664 }
665 
666 
autoconnect_console(libxl_ctx * ctx_ignored,libxl_event * ev,void * priv)667 static void autoconnect_console(libxl_ctx *ctx_ignored,
668                                 libxl_event *ev, void *priv)
669 {
670     uint32_t bldomid = ev->domid;
671     int notify_fd = *(int*)priv; /* write end of the notification pipe */
672 
673     libxl_event_free(ctx, ev);
674 
675     console_child_report(child_console);
676 
677     pid_t pid = xl_fork(child_console, "console child");
678     if (pid)
679         return;
680 
681     postfork();
682 
683     sleep(1);
684     libxl_primary_console_exec(ctx, bldomid, notify_fd, NULL);
685     /* Do not return. xl continued in child process */
686     perror("xl: unable to exec console client");
687     _exit(1);
688 }
689 
create_domain(struct domain_create * dom_info)690 int create_domain(struct domain_create *dom_info)
691 {
692     uint32_t domid = INVALID_DOMID;
693 
694     libxl_domain_config d_config;
695 
696     int debug = dom_info->debug;
697     int daemonize = dom_info->daemonize;
698     int monitor = dom_info->monitor;
699     int paused = dom_info->paused;
700     int vncautopass = dom_info->vncautopass;
701     const char *config_file = dom_info->config_file;
702     const char *extra_config = dom_info->extra_config;
703     const char *restore_file = dom_info->restore_file;
704     const char *config_source = NULL;
705     const char *restore_source = NULL;
706     int migrate_fd = dom_info->migrate_fd;
707     bool config_in_json;
708 
709     int i;
710     int need_daemon = daemonize;
711     int ret, rc;
712     libxl_evgen_domain_death *deathw = NULL;
713     libxl_evgen_disk_eject **diskws = NULL; /* one per disk */
714     unsigned int num_diskws = 0;
715     void *config_data = 0;
716     int config_len = 0;
717     int restore_fd = -1;
718     int restore_fd_to_close = -1;
719     int send_back_fd = -1;
720     const libxl_asyncprogress_how *autoconnect_console_how;
721     int notify_pipe[2] = { -1, -1 };
722     struct save_file_header hdr;
723     uint32_t domid_soft_reset = INVALID_DOMID;
724 
725     int restoring = (restore_file || (migrate_fd >= 0));
726 
727     libxl_domain_config_init(&d_config);
728 
729     if (restoring) {
730         uint8_t *optdata_begin = 0;
731         const uint8_t *optdata_here = 0;
732         union { uint32_t u32; char b[4]; } u32buf;
733         uint32_t badflags;
734 
735         if (migrate_fd >= 0) {
736             restore_source = "<incoming migration stream>";
737             restore_fd = migrate_fd;
738             send_back_fd = dom_info->send_back_fd;
739         } else {
740             restore_source = restore_file;
741             restore_fd = open(restore_file, O_RDONLY);
742             if (restore_fd == -1) {
743                 fprintf(stderr, "Can't open restore file: %s\n", strerror(errno));
744                 return ERROR_INVAL;
745             }
746             restore_fd_to_close = restore_fd;
747             rc = libxl_fd_set_cloexec(ctx, restore_fd, 1);
748             if (rc) return rc;
749         }
750 
751         CHK_ERRNOVAL(libxl_read_exactly(
752                          ctx, restore_fd, &hdr, sizeof(hdr),
753                          restore_source, "header"));
754         if (memcmp(hdr.magic, savefileheader_magic, sizeof(hdr.magic))) {
755             fprintf(stderr, "File has wrong magic number -"
756                     " corrupt or for a different tool?\n");
757             return ERROR_INVAL;
758         }
759         if (hdr.byteorder != SAVEFILE_BYTEORDER_VALUE) {
760             fprintf(stderr, "File has wrong byte order\n");
761             return ERROR_INVAL;
762         }
763         fprintf(stderr, "Loading new save file %s"
764                 " (new xl fmt info"
765                 " 0x%"PRIx32"/0x%"PRIx32"/%"PRIu32")\n",
766                 restore_source, hdr.mandatory_flags, hdr.optional_flags,
767                 hdr.optional_data_len);
768 
769         badflags = hdr.mandatory_flags & ~XL_MANDATORY_FLAG_ALL;
770         if (badflags) {
771             fprintf(stderr, "Savefile has mandatory flag(s) 0x%"PRIx32" "
772                     "which are not supported; need newer xl\n",
773                     badflags);
774             return ERROR_INVAL;
775         }
776         if (hdr.optional_data_len) {
777             optdata_begin = xmalloc(hdr.optional_data_len);
778             CHK_ERRNOVAL(libxl_read_exactly(
779                              ctx, restore_fd, optdata_begin,
780                              hdr.optional_data_len, restore_source,
781                              "optdata"));
782         }
783 
784 #define OPTDATA_LEFT  (hdr.optional_data_len - (optdata_here - optdata_begin))
785 #define WITH_OPTDATA(amt, body)                                 \
786             if (OPTDATA_LEFT < (amt)) {                         \
787                 fprintf(stderr, "Savefile truncated.\n");       \
788                 return ERROR_INVAL;                             \
789             } else {                                            \
790                 body;                                           \
791                 optdata_here += (amt);                          \
792             }
793 
794         optdata_here = optdata_begin;
795 
796         if (OPTDATA_LEFT) {
797             fprintf(stderr, " Savefile contains xl domain config%s\n",
798                     !!(hdr.mandatory_flags & XL_MANDATORY_FLAG_JSON)
799                     ? " in JSON format" : "");
800             WITH_OPTDATA(4, {
801                 memcpy(u32buf.b, optdata_here, 4);
802                 config_len = u32buf.u32;
803             });
804             WITH_OPTDATA(config_len, {
805                 config_data = xmalloc(config_len);
806                 memcpy(config_data, optdata_here, config_len);
807             });
808         }
809 
810     }
811 
812     if (config_file) {
813         free(config_data);  config_data = 0;
814         /* /dev/null represents special case (read config. from command line) */
815         if (!strcmp(config_file, "/dev/null")) {
816             config_len = 0;
817         } else {
818             ret = libxl_read_file_contents(ctx, config_file,
819                                            &config_data, &config_len);
820             if (ret) { fprintf(stderr, "Failed to read config file: %s: %s\n",
821                                config_file, strerror(errno)); return ERROR_FAIL; }
822         }
823         if (!restoring && extra_config && strlen(extra_config)) {
824             if (config_len > INT_MAX - (strlen(extra_config) + 2 + 1)) {
825                 fprintf(stderr, "Failed to attach extra configuration\n");
826                 return ERROR_FAIL;
827             }
828             /* allocate space for the extra config plus two EOLs plus \0 */
829             config_data = xrealloc(config_data, config_len
830                 + strlen(extra_config) + 2 + 1);
831             config_len += sprintf(config_data + config_len, "\n%s\n",
832                 extra_config);
833         }
834         config_source=config_file;
835         config_in_json = false;
836     } else {
837         if (!config_data) {
838             fprintf(stderr, "Config file not specified and"
839                     " none in save file\n");
840             return ERROR_INVAL;
841         }
842         config_source = "<saved>";
843         config_in_json = !!(hdr.mandatory_flags & XL_MANDATORY_FLAG_JSON);
844     }
845 
846     if (!dom_info->quiet)
847         fprintf(stderr, "Parsing config from %s\n", config_source);
848 
849     if (config_in_json) {
850         libxl_domain_config_from_json(ctx, &d_config,
851                                       (const char *)config_data);
852     } else {
853         parse_config_data(config_source, config_data, config_len, &d_config);
854     }
855 
856     if (!dom_info->ignore_global_affinity_masks) {
857         libxl_domain_build_info *b_info = &d_config.b_info;
858 
859         /* It is possible that no hard affinity is specified in config file.
860          * Generate hard affinity maps now if we care about those.
861          */
862         if (b_info->num_vcpu_hard_affinity == 0 &&
863               (!libxl_bitmap_is_full(&global_vm_affinity_mask) ||
864                  (b_info->type == LIBXL_DOMAIN_TYPE_PV &&
865                   !libxl_bitmap_is_full(&global_pv_affinity_mask)) ||
866                  (b_info->type != LIBXL_DOMAIN_TYPE_PV &&
867                   !libxl_bitmap_is_full(&global_hvm_affinity_mask))
868                )) {
869             b_info->num_vcpu_hard_affinity = b_info->max_vcpus;
870             b_info->vcpu_hard_affinity =
871                 xmalloc(b_info->max_vcpus * sizeof(libxl_bitmap));
872 
873             for (i = 0; i < b_info->num_vcpu_hard_affinity; i++) {
874                 libxl_bitmap *m = &b_info->vcpu_hard_affinity[i];
875                 libxl_bitmap_init(m);
876                 libxl_cpu_bitmap_alloc(ctx, m, 0);
877                 libxl_bitmap_set_any(m);
878             }
879         }
880 
881         apply_global_affinity_masks(b_info->type,
882                                     b_info->vcpu_hard_affinity,
883                                     b_info->num_vcpu_hard_affinity);
884     }
885 
886     if (migrate_fd >= 0) {
887         if (d_config.c_info.name) {
888             /* when we receive a domain we get its name from the config
889              * file; and we receive it to a temporary name */
890             assert(!common_domname);
891 
892             common_domname = d_config.c_info.name;
893             d_config.c_info.name = 0; /* steals allocation from config */
894 
895             xasprintf(&d_config.c_info.name, "%s--incoming", common_domname);
896             *dom_info->migration_domname_r = strdup(d_config.c_info.name);
897         }
898     }
899 
900     if (debug || dryrun_only) {
901         FILE *cfg_print_fh = (debug && !dryrun_only) ? stderr : stdout;
902         if (default_output_format == OUTPUT_FORMAT_SXP) {
903             printf_info_sexp(-1, &d_config, cfg_print_fh);
904         } else {
905             char *json = libxl_domain_config_to_json(ctx, &d_config);
906             if (!json) {
907                 fprintf(stderr,
908                         "Failed to convert domain configuration to JSON\n");
909                 exit(1);
910             }
911             fputs(json, cfg_print_fh);
912             free(json);
913             flush_stream(cfg_print_fh);
914         }
915     }
916 
917 
918     ret = 0;
919     if (dryrun_only)
920         goto out;
921 
922 start:
923     assert(domid == INVALID_DOMID);
924 
925     if (autoballoon) {
926         rc = acquire_lock();
927         if (rc < 0)
928             goto error_out;
929     }
930 
931     if (domid_soft_reset == INVALID_DOMID) {
932         if (!freemem(domid, &d_config)) {
933             fprintf(stderr, "failed to free memory for the domain\n");
934             ret = ERROR_FAIL;
935             goto error_out;
936         }
937     }
938 
939     libxl_asyncprogress_how autoconnect_console_how_buf;
940     if ( dom_info->console_autoconnect ) {
941         if (libxl_pipe(ctx, notify_pipe)) {
942             ret = ERROR_FAIL;
943             goto error_out;
944         }
945         autoconnect_console_how_buf.callback = autoconnect_console;
946         autoconnect_console_how_buf.for_callback = &notify_pipe[1];
947         autoconnect_console_how = &autoconnect_console_how_buf;
948     }else{
949         autoconnect_console_how = 0;
950     }
951 
952     if (!libxl_domid_valid_guest(d_config.c_info.domid))
953         d_config.c_info.domid = domid_policy;
954 
955     if ( restoring ) {
956         libxl_domain_restore_params params;
957 
958         libxl_domain_restore_params_init(&params);
959 
960         params.checkpointed_stream = dom_info->checkpointed_stream;
961         params.stream_version =
962             (hdr.mandatory_flags & XL_MANDATORY_FLAG_STREAMv2) ? 2 : 1;
963         params.colo_proxy_script = dom_info->colo_proxy_script;
964         libxl_defbool_set(&params.userspace_colo_proxy,
965                           dom_info->userspace_colo_proxy);
966 
967         ret = libxl_domain_create_restore(ctx, &d_config,
968                                           &domid, restore_fd,
969                                           send_back_fd, &params,
970                                           0, autoconnect_console_how);
971 
972         libxl_domain_restore_params_dispose(&params);
973 
974         /*
975          * On subsequent reboot etc we should create the domain, not
976          * restore/migrate-receive it again.
977          */
978         restoring = 0;
979     } else if (domid_soft_reset != INVALID_DOMID) {
980         /* Do soft reset. */
981         ret = libxl_domain_soft_reset(ctx, &d_config, domid_soft_reset,
982                                       0, autoconnect_console_how);
983         domid = domid_soft_reset;
984         domid_soft_reset = INVALID_DOMID;
985     } else {
986         ret = libxl_domain_create_new(ctx, &d_config, &domid,
987                                       0, autoconnect_console_how);
988     }
989     if ( ret )
990         goto error_out;
991 
992     if (autoballoon)
993         release_lock();
994 
995     if (restore_fd_to_close >= 0) {
996         if (close(restore_fd_to_close))
997             fprintf(stderr, "Failed to close restoring file, fd %d, errno %d\n",
998                     restore_fd_to_close, errno);
999         restore_fd_to_close = -1;
1000     }
1001 
1002     if (autoconnect_console_how) {
1003         char buf[1];
1004         int r;
1005 
1006         /* Try to get notification from xenconsole. Just move on if
1007          * error occurs -- it's only minor annoyance if console
1008          * doesn't show up.
1009          */
1010         do {
1011             r = read(notify_pipe[0], buf, 1);
1012         } while (r == -1 && errno == EINTR);
1013 
1014         if (r == -1)
1015             fprintf(stderr,
1016                     "Failed to get notification from xenconsole: %s\n",
1017                     strerror(errno));
1018         else if (r == 0)
1019             fprintf(stderr, "Got EOF from xenconsole notification fd\n");
1020         else if (r == 1 && buf[0] != 0x00)
1021             fprintf(stderr, "Got unexpected response from xenconsole: %#x\n",
1022                     buf[0]);
1023 
1024         close(notify_pipe[0]);
1025         close(notify_pipe[1]);
1026         notify_pipe[0] = notify_pipe[1] = -1;
1027     }
1028 
1029     if (!paused)
1030         libxl_domain_unpause(ctx, domid, NULL);
1031 
1032     ret = domid; /* caller gets success in parent */
1033     if (!daemonize && !monitor)
1034         goto out;
1035 
1036     if (dom_info->vnc)
1037         autoconnect_vncviewer(domid, vncautopass);
1038 
1039     if (need_daemon) {
1040         char *name;
1041 
1042         xasprintf(&name, "xl-%s", d_config.c_info.name);
1043         ret = do_daemonize(name, NULL);
1044         free(name);
1045         if (ret) {
1046             ret = (ret == 1) ? domid : ret;
1047             goto out;
1048         }
1049         need_daemon = 0;
1050     }
1051     LOG("Waiting for domain %s (domid %u) to die [pid %ld]",
1052         d_config.c_info.name, domid, (long)getpid());
1053 
1054     ret = libxl_evenable_domain_death(ctx, domid, 0, &deathw);
1055     if (ret) goto out;
1056 
1057     if (!diskws) {
1058         diskws = xmalloc(sizeof(*diskws) * d_config.num_disks);
1059         for (i = 0; i < d_config.num_disks; i++)
1060             diskws[i] = NULL;
1061         num_diskws = d_config.num_disks;
1062     }
1063     for (i = 0; i < num_diskws; i++) {
1064         if (d_config.disks[i].removable) {
1065             ret = libxl_evenable_disk_eject(ctx, domid, d_config.disks[i].vdev,
1066                                             0, &diskws[i]);
1067             if (ret) goto out;
1068         }
1069     }
1070     while (1) {
1071         libxl_evgen_domain_death *deathw2 = NULL;
1072         libxl_event *event;
1073         ret = domain_wait_event(domid, &event);
1074         if (ret) goto out;
1075 
1076         switch (event->type) {
1077 
1078         case LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN:
1079             LOG("Domain %u has shut down, reason code %d 0x%x", domid,
1080                 event->u.domain_shutdown.shutdown_reason,
1081                 event->u.domain_shutdown.shutdown_reason);
1082             switch (handle_domain_death(&domid, event, &d_config)) {
1083             case DOMAIN_RESTART_SOFT_RESET:
1084                 domid_soft_reset = domid;
1085                 domid = INVALID_DOMID;
1086                 /* fall through */
1087             case DOMAIN_RESTART_RENAME:
1088                 if (domid_soft_reset == INVALID_DOMID &&
1089                     !preserve_domain(&domid, event, &d_config)) {
1090                     libxl_event_free(ctx, event);
1091                     /* If we fail then exit leaving the old domain in place. */
1092                     ret = -1;
1093                     goto out;
1094                 }
1095 
1096                 /* Otherwise fall through and restart. */
1097             case DOMAIN_RESTART_NORMAL:
1098                 libxl_event_free(ctx, event);
1099                 libxl_evdisable_domain_death(ctx, deathw);
1100                 deathw = NULL;
1101                 evdisable_disk_ejects(diskws, num_diskws);
1102                 free(diskws);
1103                 diskws = NULL;
1104                 num_diskws = 0;
1105                 /* discard any other events which may have been generated */
1106                 while (!(ret = libxl_event_check(ctx, &event,
1107                                                  LIBXL_EVENTMASK_ALL, 0,0))) {
1108                     libxl_event_free(ctx, event);
1109                 }
1110                 if (ret != ERROR_NOT_READY) {
1111                     LOG("warning, libxl_event_check (cleanup) failed (rc=%d)",
1112                         ret);
1113                 }
1114 
1115                 /*
1116                  * Do not attempt to reconnect if we come round again due to a
1117                  * guest reboot -- the stdin/out will be disconnected by then.
1118                  */
1119                 dom_info->console_autoconnect = 0;
1120 
1121                 /* Some settings only make sense on first boot. */
1122                 paused = 0;
1123                 if (common_domname
1124                     && strcmp(d_config.c_info.name, common_domname)) {
1125                     d_config.c_info.name = strdup(common_domname);
1126                 }
1127 
1128                 /*
1129                  * XXX FIXME: If this sleep is not there then domain
1130                  * re-creation fails sometimes.
1131                  */
1132                 LOG("Done. Rebooting now");
1133                 sleep(2);
1134                 goto start;
1135 
1136             case DOMAIN_RESTART_NONE:
1137                 LOG("Done. Exiting now");
1138                 libxl_event_free(ctx, event);
1139                 ret = 0;
1140                 goto out;
1141 
1142             case DOMAIN_RESTART_SUSPENDED:
1143                 LOG("Continue waiting for domain %u", domid);
1144                 /*
1145                  * Enable a new event before disabling the old.  This ensures
1146                  * the xenstore watch remains active.  Otherwise it'll fire
1147                  * immediately on re-registration and find our suspended domain.
1148                  */
1149                 ret = libxl_evenable_domain_death(ctx, domid, 0, &deathw2);
1150                 if (ret) goto out;
1151                 libxl_evdisable_domain_death(ctx, deathw);
1152                 deathw = deathw2;
1153                 deathw2 = NULL;
1154                 break;
1155 
1156             default:
1157                 abort();
1158             }
1159             break;
1160 
1161         case LIBXL_EVENT_TYPE_DOMAIN_DEATH:
1162             LOG("Domain %u has been destroyed.", domid);
1163             libxl_event_free(ctx, event);
1164             ret = 0;
1165             goto out;
1166 
1167         case LIBXL_EVENT_TYPE_DISK_EJECT:
1168             /* XXX what is this for? */
1169             libxl_cdrom_insert(ctx, domid, &event->u.disk_eject.disk, NULL);
1170             break;
1171 
1172         default:;
1173             char *evstr = libxl_event_to_json(ctx, event);
1174             LOG("warning, got unexpected event type %d, event=%s",
1175                 event->type, evstr);
1176             free(evstr);
1177         }
1178 
1179         libxl_event_free(ctx, event);
1180     }
1181 
1182 error_out:
1183     if (autoballoon)
1184         release_lock();
1185     if (libxl_domid_valid_guest(domid)) {
1186         libxl_domain_destroy(ctx, domid, 0);
1187         domid = INVALID_DOMID;
1188     }
1189 
1190 out:
1191     if (restore_fd_to_close >= 0) {
1192         if (close(restore_fd_to_close))
1193             fprintf(stderr, "Failed to close restoring file, fd %d, errno %d\n",
1194                     restore_fd_to_close, errno);
1195         restore_fd_to_close = -1;
1196     }
1197 
1198     if (logfile != 2)
1199         close(logfile);
1200 
1201     libxl_domain_config_dispose(&d_config);
1202 
1203     free(config_data);
1204 
1205     console_child_report(child_console);
1206 
1207     if (deathw)
1208         libxl_evdisable_domain_death(ctx, deathw);
1209     if (diskws) {
1210         evdisable_disk_ejects(diskws, d_config.num_disks);
1211         free(diskws);
1212     }
1213 
1214     /*
1215      * If we have daemonized then do not return to the caller -- this has
1216      * already happened in the parent.
1217      */
1218     if ( daemonize && !need_daemon )
1219         exit(ret);
1220 
1221     return ret;
1222 }
1223 
main_create(int argc,char ** argv)1224 int main_create(int argc, char **argv)
1225 {
1226     struct domain_create dom_info = {
1227         /* Command-line options */
1228         .config_file = NULL,
1229         .console_autoconnect = 0,
1230         .debug = 0,
1231         .daemonize = 1,
1232         .ignore_global_affinity_masks = 0,
1233         .monitor = 1,
1234         .paused = 0,
1235         .quiet = 0,
1236         .vnc = 0,
1237         .vncautopass = 0,
1238 
1239         /* Extra configuration file settings */
1240         .extra_config = NULL,
1241 
1242         /* FDs, initialize to invalid */
1243         .migrate_fd = -1,
1244         .send_back_fd = -1,
1245     };
1246     int opt, rc;
1247     static const struct option opts[] = {
1248         {"defconfig", 1, 0, 'f'},
1249         {"dryrun", 0, 0, 'n'},
1250         {"ignore-global-affinity-masks", 0, 0, 'i'},
1251         {"quiet", 0, 0, 'q'},
1252         {"vncviewer", 0, 0, 'V'},
1253         {"vncviewer-autopass", 0, 0, 'A'},
1254         COMMON_LONG_OPTS
1255     };
1256 
1257     if (argv[1] && argv[1][0] != '-' && !strchr(argv[1], '=')) {
1258         dom_info.config_file = argv[1];
1259         argc--; argv++;
1260     }
1261 
1262     SWITCH_FOREACH_OPT(opt, "AFVcdef:inpq", opts, "create", 0) {
1263     case 'A':
1264         dom_info.vnc = dom_info.vncautopass = 1;
1265         break;
1266     case 'F':
1267         dom_info.daemonize = 0;
1268         break;
1269     case 'V':
1270         dom_info.vnc = 1;
1271         break;
1272     case 'c':
1273         dom_info.console_autoconnect = 1;
1274         break;
1275     case 'd':
1276         dom_info.debug = 1;
1277         break;
1278     case 'e':
1279         dom_info.daemonize = 0;
1280         dom_info.monitor = 0;
1281         break;
1282     case 'f':
1283         dom_info.config_file = optarg;
1284         break;
1285     case 'i':
1286         dom_info.ignore_global_affinity_masks = 1;
1287         break;
1288     case 'n':
1289         dryrun_only = 1;
1290         break;
1291     case 'p':
1292         dom_info.paused = 1;
1293         break;
1294     case 'q':
1295         dom_info.quiet = 1;
1296         break;
1297     }
1298 
1299     for (; optind < argc; optind++) {
1300         if (strchr(argv[optind], '=') != NULL) {
1301             string_realloc_append(&dom_info.extra_config, argv[optind]);
1302             string_realloc_append(&dom_info.extra_config, "\n");
1303         } else if (!dom_info.config_file) {
1304             dom_info.config_file = argv[optind];
1305         } else {
1306             help("create");
1307             free(dom_info.extra_config);
1308             return 2;
1309         }
1310     }
1311 
1312     rc = create_domain(&dom_info);
1313     if (rc < 0) {
1314         free(dom_info.extra_config);
1315         return -rc;
1316     }
1317 
1318     free(dom_info.extra_config);
1319     return 0;
1320 }
1321 
1322 #ifdef LIBXL_HAVE_DT_OVERLAY
main_dt_overlay(int argc,char ** argv)1323 int main_dt_overlay(int argc, char **argv)
1324 {
1325     const char *overlay_config_file = NULL;
1326     void *overlay_dtb = NULL;
1327     int rc;
1328     uint8_t op;
1329     int overlay_dtb_size = 0;
1330     uint32_t domain_id = 0;
1331     bool domain_op = false;
1332 
1333     if (argc < 2) {
1334         help("dt-overlay");
1335         return EXIT_FAILURE;
1336     }
1337 
1338     if (strcmp(argv[optind], "add") == 0)
1339         op = LIBXL_DT_OVERLAY_ADD;
1340     else if (strcmp(argv[optind], "remove") == 0)
1341         op = LIBXL_DT_OVERLAY_REMOVE;
1342     else if (strcmp(argv[optind], "attach") == 0) {
1343         op = LIBXL_DT_OVERLAY_DOMAIN_ATTACH;
1344         domain_op = true;
1345     } else {
1346         fprintf(stderr, "Invalid dt overlay operation\n");
1347         return EXIT_FAILURE;
1348     }
1349 
1350     overlay_config_file = argv[optind+1];
1351 
1352     if (domain_op) {
1353         if (argc <= optind + 2) {
1354             fprintf(stderr, "Missing domain ID\n");
1355             help("dt-overlay");
1356             return EXIT_FAILURE;
1357         } else {
1358             domain_id = find_domain(argv[optind+2]);
1359         }
1360     }
1361 
1362     if (overlay_config_file) {
1363         rc = libxl_read_file_contents(ctx, overlay_config_file,
1364                                       &overlay_dtb, &overlay_dtb_size);
1365 
1366         if (rc) {
1367             fprintf(stderr, "failed to read the overlay device tree file %s\n",
1368                     overlay_config_file);
1369             free(overlay_dtb);
1370             return EXIT_FAILURE;
1371         }
1372     } else {
1373         fprintf(stderr, "overlay dtbo file not provided\n");
1374         return EXIT_FAILURE;
1375     }
1376 
1377     if (!domain_op)
1378         rc = libxl_dt_overlay(ctx, overlay_dtb, overlay_dtb_size, op);
1379     else
1380         rc = libxl_dt_overlay_domain(ctx, domain_id, overlay_dtb,
1381                                      overlay_dtb_size, op);
1382 
1383     free(overlay_dtb);
1384 
1385     if (rc)
1386         return EXIT_FAILURE;
1387 
1388     return rc;
1389 }
1390 #endif
1391 
1392 /*
1393  * Local variables:
1394  * mode: C
1395  * c-basic-offset: 4
1396  * indent-tabs-mode: nil
1397  * End:
1398  */
1399