qq2clone/lv_api_do.c

310 lines
8.7 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libvirt/libvirt.h>
/*
#------------------------------------------------------------------------#
# 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/>. #
#------------------------------------------------------------------------#
*/
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
by the requested information, then EOF */
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 () {
setlinebuf(stdout); /* Make sure output is always line buffered */
conn=virConnectOpen(NULL); /* Connect to libvirt API */
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() {
printf("%s\n",BAD_REQ);
}
void pr_conn_bad() {
printf("%s\n", CONN_BAD);
}
void pr_conn_good() {
printf("%s\n",CONN_GOOD);
}
/* Okay, this one provides a basic output sequence *and* quits */
void pr_fatal_and_exit(int e) {
printf("%s\n",FATAL);
virConnectClose;
exit(e);
}
void pr_good() {
printf("%s\n",GOOD);
}
void pr_no_match() {
printf("%s\n",NOMATCH);
}
/*****************************************
* 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);
printf("EOF\n");
}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);
printf("EOF\n");
}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);
} else { pr_fatal_and_exit(E_LIBVIRT); }
virDomainFree(domain);
printf("EOF\n");
} else {
pr_no_match();
}
}
void lv_list_all_uuid() {
virDomainPtr *domains;
int ret_list, ret_uuid, i;
ret_list=virConnectListAllDomains(conn,&domains,0);
if(ret_list<0){ virConnectClose(conn);
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);
}
virDomainFree(domains[i]);
}
free(uuid);
free(domains);
printf("EOF\n");
}
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);
printf("EOF\n");
}