2021-03-22 22:26:41 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2021-04-25 16:48:08 +00:00
|
|
|
#include <libvirt/libvirt.h>
|
2021-03-22 22:26:41 +00:00
|
|
|
|
2021-07-16 01:56:36 +00:00
|
|
|
/*
|
|
|
|
#------------------------------------------------------------------------#
|
|
|
|
# Copyright 2021, Jesse Gardner #
|
|
|
|
#------------------------------------------------------------------------#
|
|
|
|
# This file is part of qq2clone. #
|
|
|
|
# #
|
|
|
|
# qq2clone is free software: you can redistribute it and/or modify #
|
|
|
|
# it under the terms of the GNU General Public License as published by #
|
|
|
|
# the Free Software Foundation, either version 2 of the License, or #
|
|
|
|
# (at your option) any later version. #
|
|
|
|
# #
|
|
|
|
# qq2clone is distributed in the hope that it will be useful, #
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
|
|
|
# GNU General Public License for more details. #
|
|
|
|
# #
|
|
|
|
# You should have received a copy of the GNU General Public License #
|
|
|
|
# along with qq2clone. If not, see <https://www.gnu.org/licenses/>. #
|
|
|
|
#------------------------------------------------------------------------#
|
|
|
|
*/
|
|
|
|
|
2021-03-22 22:26:41 +00:00
|
|
|
void pr_bad();
|
|
|
|
void pr_conn_bad();
|
|
|
|
void pr_conn_good();
|
|
|
|
void pr_fatal_and_exit(int e);
|
|
|
|
void pr_good();
|
|
|
|
void pr_no_match();
|
|
|
|
|
|
|
|
int get_domain(char *uuid, virDomainPtr *domain);
|
|
|
|
char * get_state_string(virDomainPtr dom, int state);
|
|
|
|
|
|
|
|
void lv_get_name(char *uuid);
|
|
|
|
void lv_get_state(char *uuid);
|
|
|
|
void lv_get_xml(char *uuid);
|
|
|
|
void lv_list_all_name();
|
|
|
|
void lv_list_all_uuid();
|
|
|
|
|
|
|
|
const int E_LIBVIRT=16;
|
|
|
|
virConnectPtr conn;
|
|
|
|
|
|
|
|
/*One of these is displayed on startup. If CONN_BAD, program exits*/
|
|
|
|
const char CONN_BAD[]= "# No Connection";
|
|
|
|
const char CONN_GOOD[]="# Connected";
|
|
|
|
|
|
|
|
/*After a command is issued, one of these displays. Only GOOD is followed
|
2021-03-23 01:24:54 +00:00
|
|
|
by the requested information, then EOF */
|
2021-03-22 22:26:41 +00:00
|
|
|
const char BAD_REQ[]="# Bad Request";
|
|
|
|
const char FATAL[]= "# Fatal error";
|
|
|
|
const char GOOD[]= "# Making API Request";
|
|
|
|
const char NOMATCH[]="# No matching domain";
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
|
|
/* Possible commands:
|
|
|
|
* list: list UUIDs of all domains that are defined and/or running
|
|
|
|
* list_name: list names of all domains that are defined and/or running
|
|
|
|
* get_name <uuid>: get name of domain
|
|
|
|
* get_state <uuid>: get state of domain as defined in man qq2clone. It
|
|
|
|
* is possible, though unlikely for this to return an empty string
|
|
|
|
* even when referring to a valid uuid
|
|
|
|
* get_xml <uuid>: print xml file describing domain (prints current
|
|
|
|
* config of a running machine, rather than inactive config)
|
|
|
|
*/
|
|
|
|
|
|
|
|
int main () {
|
2021-03-23 01:24:54 +00:00
|
|
|
setlinebuf(stdout); /* Make sure output is always line buffered */
|
2021-04-25 16:48:08 +00:00
|
|
|
conn=virConnectOpen(NULL); /* Connect to libvirt API */
|
2021-03-22 22:26:41 +00:00
|
|
|
if ( conn == NULL) {
|
|
|
|
pr_conn_bad();
|
|
|
|
exit(E_LIBVIRT);
|
|
|
|
} else {
|
|
|
|
pr_conn_good();
|
|
|
|
}
|
|
|
|
|
|
|
|
char *lineptr, *token, **str_arr;
|
|
|
|
const char delim[]="\t\n ";
|
|
|
|
unsigned int count;
|
|
|
|
int i;
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
/* Get input from stdin and execute commands in a loop */
|
|
|
|
while(1) {
|
|
|
|
str_arr=NULL;
|
|
|
|
lineptr=NULL; n=0; count=0;
|
|
|
|
|
|
|
|
getline(&lineptr,&n,stdin);
|
|
|
|
token=strtok(lineptr,delim);
|
|
|
|
if (token == NULL) { free(lineptr); pr_bad(); continue; }
|
|
|
|
|
|
|
|
while (token != NULL) {
|
|
|
|
str_arr=realloc(str_arr, sizeof(char*) * (count + 1) );
|
|
|
|
if (str_arr == NULL){ pr_fatal_and_exit(1); }
|
|
|
|
str_arr[count]=token;
|
|
|
|
count++;
|
|
|
|
token=strtok(NULL,delim);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( count > 2 || count == 0) { free(lineptr); pr_bad(); continue; }
|
|
|
|
if ( strcmp( str_arr[0], "exit" ) == 0 ) {
|
|
|
|
virConnectClose(conn); exit(0);
|
|
|
|
|
|
|
|
} else if (strcmp( str_arr[0], "list" ) == 0 ) {
|
|
|
|
if (count==1){ lv_list_all_uuid(); } else { pr_bad(); }
|
|
|
|
|
|
|
|
} else if (strcmp( str_arr[0], "list_name" ) == 0 ) {
|
|
|
|
if (count==1){ lv_list_all_name(); } else { pr_bad(); }
|
|
|
|
|
|
|
|
} else if (strcmp( str_arr[0], "get_name" ) == 0 ) {
|
|
|
|
if (count==2){ lv_get_name(str_arr[1]); } else { pr_bad(); }
|
|
|
|
|
|
|
|
} else if (strcmp( str_arr[0], "get_state" ) == 0 ) {
|
|
|
|
if (count==2){ lv_get_state(str_arr[1]); } else { pr_bad(); }
|
|
|
|
|
|
|
|
} else if (strcmp( str_arr[0], "get_xml" ) == 0 ) {
|
|
|
|
if (count==2){ lv_get_xml(str_arr[1]); } else { pr_bad(); }
|
|
|
|
|
|
|
|
} else {
|
|
|
|
pr_bad();
|
|
|
|
}
|
|
|
|
|
|
|
|
free(lineptr);
|
|
|
|
if (str_arr != NULL){ free(str_arr); }
|
|
|
|
}
|
|
|
|
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
|
|
/***********************************
|
|
|
|
* Basic, repeated output sequences *
|
|
|
|
***********************************/
|
|
|
|
|
|
|
|
void pr_bad() {
|
2021-03-23 01:24:54 +00:00
|
|
|
printf("%s\n",BAD_REQ);
|
2021-03-22 22:26:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void pr_conn_bad() {
|
2021-03-23 01:24:54 +00:00
|
|
|
printf("%s\n", CONN_BAD);
|
2021-03-22 22:26:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void pr_conn_good() {
|
2021-03-23 01:24:54 +00:00
|
|
|
printf("%s\n",CONN_GOOD);
|
2021-03-22 22:26:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Okay, this one provides a basic output sequence *and* quits */
|
|
|
|
void pr_fatal_and_exit(int e) {
|
2021-03-23 01:24:54 +00:00
|
|
|
printf("%s\n",FATAL);
|
2021-03-22 22:26:41 +00:00
|
|
|
virConnectClose;
|
|
|
|
exit(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void pr_good() {
|
2021-03-23 01:24:54 +00:00
|
|
|
printf("%s\n",GOOD);
|
2021-03-22 22:26:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void pr_no_match() {
|
2021-03-23 01:24:54 +00:00
|
|
|
printf("%s\n",NOMATCH);
|
2021-03-22 22:26:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************
|
|
|
|
* Helper functions for working with API *
|
|
|
|
*****************************************/
|
|
|
|
|
|
|
|
int get_domain(char *uuid, virDomainPtr *domain){
|
|
|
|
*domain=virDomainLookupByUUIDString(conn, (const char *) uuid);
|
|
|
|
if (domain == NULL){
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char * get_state_string(virDomainPtr dom, int state)
|
|
|
|
{
|
|
|
|
if (state == VIR_DOMAIN_RUNNING) {
|
|
|
|
return ("running");
|
|
|
|
} else if (state == VIR_DOMAIN_BLOCKED) {
|
|
|
|
return ("idle");
|
|
|
|
} else if ( state == VIR_DOMAIN_PAUSED ) {
|
|
|
|
return ("paused");
|
|
|
|
} else if ( state == VIR_DOMAIN_SHUTDOWN ) {
|
|
|
|
return("shutting-down");
|
|
|
|
} else if ( state == VIR_DOMAIN_SHUTOFF ) {
|
|
|
|
int saved;
|
|
|
|
saved=virDomainHasManagedSaveImage(dom,0);
|
|
|
|
if( saved == 1 ) {
|
|
|
|
return("saved");
|
|
|
|
} else if ( saved == 0 ) {
|
|
|
|
return("off");
|
|
|
|
} else {
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
} else if ( state == VIR_DOMAIN_CRASHED ) {
|
|
|
|
return("crashed");
|
|
|
|
} else if ( state == VIR_DOMAIN_PMSUSPENDED ) {
|
|
|
|
return ("pmsuspended");
|
|
|
|
} else {
|
|
|
|
return("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************
|
|
|
|
* Get information from libvirt API and print to stdout *
|
|
|
|
*******************************************************/
|
|
|
|
|
|
|
|
void lv_get_name (char *uuid){
|
|
|
|
virDomainPtr domain;
|
|
|
|
if (get_domain(uuid, &domain) == 0){
|
|
|
|
pr_good();
|
|
|
|
const char *name;
|
|
|
|
name=virDomainGetName(domain);
|
|
|
|
if (name!=NULL){ printf("+%s\n",name); }
|
|
|
|
else { pr_fatal_and_exit(E_LIBVIRT); }
|
|
|
|
virDomainFree(domain);
|
2021-03-23 01:24:54 +00:00
|
|
|
printf("EOF\n");
|
2021-03-22 22:26:41 +00:00
|
|
|
}else{
|
|
|
|
pr_no_match();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void lv_get_state(char *uuid){
|
|
|
|
virDomainPtr domain;
|
|
|
|
if (get_domain(uuid, &domain) == 0){
|
|
|
|
pr_good();
|
|
|
|
int *state=malloc(sizeof(state)), *reason=malloc(sizeof(reason)), ret;
|
|
|
|
ret=virDomainGetState(domain,state,reason,0);
|
|
|
|
if ( ret==0 ){
|
|
|
|
const char *state_str;
|
|
|
|
state_str=get_state_string(domain, *state);
|
|
|
|
printf("+%s\n",state_str);
|
|
|
|
} else { printf("+\n"); }
|
|
|
|
virDomainFree(domain);
|
|
|
|
free(state);
|
|
|
|
free(reason);
|
2021-03-23 01:24:54 +00:00
|
|
|
printf("EOF\n");
|
2021-03-22 22:26:41 +00:00
|
|
|
}else{
|
|
|
|
pr_no_match();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void lv_get_xml(char *uuid){
|
|
|
|
virDomainPtr domain;
|
|
|
|
if (get_domain(uuid, &domain) == 0){
|
|
|
|
pr_good();
|
|
|
|
char *xml;
|
|
|
|
xml=virDomainGetXMLDesc(domain, 0);
|
|
|
|
if ( xml!=NULL ){
|
|
|
|
char *token;
|
|
|
|
token=strtok(xml, "\n");
|
|
|
|
if(token==NULL) { free(xml); virDomainFree(domain); return; }
|
|
|
|
|
|
|
|
while (token != NULL) {
|
|
|
|
printf ("+%s\n",token);
|
|
|
|
token=strtok(NULL, "\n");
|
|
|
|
}
|
|
|
|
free(xml);
|
2021-03-23 01:24:54 +00:00
|
|
|
} else { pr_fatal_and_exit(E_LIBVIRT); }
|
2021-03-22 22:26:41 +00:00
|
|
|
virDomainFree(domain);
|
2021-03-23 01:24:54 +00:00
|
|
|
printf("EOF\n");
|
|
|
|
} else {
|
2021-03-22 22:26:41 +00:00
|
|
|
pr_no_match();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void lv_list_all_uuid() {
|
|
|
|
virDomainPtr *domains;
|
|
|
|
int ret_list, ret_uuid, i;
|
|
|
|
ret_list=virConnectListAllDomains(conn,&domains,0);
|
2021-03-23 01:24:54 +00:00
|
|
|
if(ret_list<0){ virConnectClose(conn);
|
2021-03-22 22:26:41 +00:00
|
|
|
pr_fatal_and_exit(E_LIBVIRT); };
|
|
|
|
pr_good();
|
|
|
|
|
|
|
|
char *uuid=malloc(VIR_UUID_STRING_BUFLEN);
|
|
|
|
for(i=0;i<ret_list;i++){
|
|
|
|
ret_uuid=virDomainGetUUIDString(domains[i],uuid);
|
|
|
|
if (ret_uuid==0) {
|
|
|
|
printf("+%s\n",uuid);
|
|
|
|
}
|
2021-03-23 01:24:54 +00:00
|
|
|
virDomainFree(domains[i]);
|
2021-03-22 22:26:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free(uuid);
|
|
|
|
free(domains);
|
2021-03-23 01:24:54 +00:00
|
|
|
printf("EOF\n");
|
2021-03-22 22:26:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lv_list_all_name() {
|
|
|
|
virDomainPtr *domains;
|
|
|
|
int ret_list, i;
|
|
|
|
ret_list=virConnectListAllDomains(conn,&domains,0);
|
|
|
|
if(ret_list<0){ virConnectClose(conn); pr_fatal_and_exit(E_LIBVIRT); };
|
|
|
|
pr_good();
|
|
|
|
|
|
|
|
const char *name;
|
|
|
|
for(i=0;i<ret_list;i++){
|
|
|
|
name=virDomainGetName(domains[i]);
|
|
|
|
if (name!=NULL){ printf("+%s\n",name); }
|
|
|
|
else { pr_fatal_and_exit(E_LIBVIRT); }
|
|
|
|
virDomainFree(domains[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(domains);
|
2021-03-23 01:24:54 +00:00
|
|
|
printf("EOF\n");
|
2021-03-22 22:26:41 +00:00
|
|
|
}
|