Skip to content

Instantly share code, notes, and snippets.

@CodeCouturiers
Last active February 3, 2025 20:18
Show Gist options
  • Save CodeCouturiers/35299d14e2ddad6df6ab9e9d8dacf5ca to your computer and use it in GitHub Desktop.
Save CodeCouturiers/35299d14e2ddad6df6ab9e9d8dacf5ca to your computer and use it in GitHub Desktop.
/*
* This demonstrates how to interact with a VMware virtual machine using VIX API.
* It performs various guest operations on a Linux VM including:
* - Getting system information using 'uname'
* - Getting current directory using 'pwd'
* - Handling file operations and command execution
*/
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include "vix.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
/*
* Guest OS credentials
*/
#define GUEST_USERNAME "user"
#define GUEST_PASSWORD "user"
/*
* Connection settings for VMware Workstation
*/
#define CONNTYPE VIX_SERVICEPROVIDER_VMWARE_WORKSTATION
#define HOSTNAME ""
#define HOSTPORT 0
#define USERNAME ""
#define PASSWORD ""
#define VMPOWEROPTIONS VIX_VMPOWEROP_LAUNCH_GUI
#define TOOLS_TIMEOUT 60
#define VMX_PATH "C:\\Users\\user\\Documents\\Virtual Machines\\Ubuntu 64-bit Server\\Ubuntu 64-bit Server.vmx"
/*
* Error handling function
*/
static void handleVixError(VixError err, const char* operation) {
if (VIX_FAILED(err)) {
const char* errorText = Vix_GetErrorText(err, NULL);
fprintf(stderr, "%s failed: %s\n", operation, errorText);
Vix_FreeBuffer((void*)errorText);
}
}
/*
* Function to execute command and get output via temporary file
*/
static char* runCommandAndGetOutput(VixHandle vmHandle, const char* command, const char* args) {
VixError err;
VixHandle jobHandle;
char* result = NULL;
const char* tempGuestFile = "/tmp/command_output.txt";
const char* tempHostFile = "command_output.txt";
FILE* file = NULL;
errno_t fileErr;
// Execute command with output redirection
jobHandle = VixVM_RunProgramInGuest(vmHandle,
command,
args,
0,
VIX_INVALID_HANDLE,
NULL,
NULL);
err = VixJob_Wait(jobHandle, VIX_PROPERTY_NONE);
Vix_ReleaseHandle(jobHandle);
if (VIX_FAILED(err)) {
handleVixError(err, "Running command");
goto cleanup;
}
// Copy the file from guest to host
jobHandle = VixVM_CopyFileFromGuestToHost(vmHandle,
tempGuestFile,
tempHostFile,
0,
VIX_INVALID_HANDLE,
NULL,
NULL);
err = VixJob_Wait(jobHandle, VIX_PROPERTY_NONE);
Vix_ReleaseHandle(jobHandle);
if (VIX_FAILED(err)) {
handleVixError(err, "Copying file from guest");
goto cleanup;
}
// Read the local file using secure file operations
fileErr = fopen_s(&file, tempHostFile, "r");
if (fileErr == 0 && file != NULL) {
// Get file size
if (fseek(file, 0, SEEK_END) == 0) {
long fileSize = ftell(file);
if (fileSize != -1 && fseek(file, 0, SEEK_SET) == 0) {
// Allocate memory for the content
result = (char*)malloc(fileSize + 1);
if (result) {
size_t bytesRead = fread(result, 1, fileSize, file);
result[bytesRead] = '\0';
}
}
}
fclose(file);
remove(tempHostFile); // Delete the temporary host file
}
cleanup:
// Cleanup temporary file in guest
jobHandle = VixVM_RunProgramInGuest(vmHandle,
"rm",
tempGuestFile,
0,
VIX_INVALID_HANDLE,
NULL,
NULL);
Vix_ReleaseHandle(jobHandle);
return result;
}
/*
* Function to monitor command output in real-time
*/
static void monitorCommandOutput(VixHandle vmHandle, const char* command, int intervalMs) {
char* lastOutput = NULL;
size_t lastOutputLen = 0;
while (true) {
char* currentOutput = runCommandAndGetOutput(vmHandle,
"/bin/cat",
"/tmp/command_output.txt");
if (currentOutput) {
size_t currentLen = strlen(currentOutput);
// Print only new content
if (currentLen > lastOutputLen) {
printf("%s", currentOutput + lastOutputLen);
fflush(stdout); // Ensure output is displayed immediately
// Update last output
free(lastOutput);
lastOutput = currentOutput;
lastOutputLen = currentLen;
} else {
free(currentOutput);
}
}
// Check if command has finished
char* exitCodeStr = runCommandAndGetOutput(vmHandle, "/bin/cat", "/tmp/exit_code.txt");
if (exitCodeStr) {
free(exitCodeStr);
break;
}
// Sleep for specified interval
#ifdef _WIN32
Sleep(intervalMs);
#else
usleep(intervalMs * 1000);
#endif
}
free(lastOutput);
}
/*
* Helper function to execute sudo commands
*/
static char* executeSudoCommand(VixHandle vmHandle, const char* command) {
char checkBuffer[1024];
// Используем SUDO_ASKPASS для автоматического ввода пароля
snprintf(checkBuffer, sizeof(checkBuffer),
"-c 'export SUDO_ASKPASS=/tmp/askpass.sh; "
"echo \"#!/bin/bash\necho %s\" > /tmp/askpass.sh; "
"chmod +x /tmp/askpass.sh; "
"sudo -A %s 2>&1 | tee /tmp/command_output.txt; "
"rm /tmp/askpass.sh; "
"echo $? > /tmp/exit_code.txt'",
GUEST_PASSWORD,
command);
// Запускаем команду асинхронно
VixHandle jobHandle = VixVM_RunProgramInGuest(vmHandle,
"/bin/bash",
checkBuffer,
0,
VIX_INVALID_HANDLE,
NULL,
NULL);
// Мониторим вывод в реальном времени
monitorCommandOutput(vmHandle, command, 20); // 20ms interval
// Получаем финальный результат
char* output = runCommandAndGetOutput(vmHandle, "/bin/cat", "/tmp/command_output.txt");
// Проверяем код возврата
char* exitCode = runCommandAndGetOutput(vmHandle, "/bin/cat", "/tmp/exit_code.txt");
if (exitCode) {
int status = atoi(exitCode);
free(exitCode);
if (status != 0) {
printf("\nCommand failed with status: %d\n", status);
if (output) {
free(output);
output = NULL;
}
}
}
return output;
}
/*
* Helper function to wait for apt lock release
*/
static bool waitForAptLock(VixHandle vmHandle) {
const int maxAttempts = 5; // Maximum wait time: 30 seconds
const int waitInterval = 1000; // Wait interval: 1 second
printf("Waiting for apt locks to be released...\n");
for (int attempt = 0; attempt < maxAttempts; attempt++) {
// Проверяем блокировки с помощью простого теста
char* result = runCommandAndGetOutput(vmHandle,
"/bin/bash",
"-c '[ ! -f /var/lib/dpkg/lock ] && [ ! -f /var/lib/apt/lists/lock ] && echo \"LOCKS_FREE\"'");
if (result) {
if (strstr(result, "LOCKS_FREE")) {
printf("All apt locks are free\n");
free(result);
return true;
} else {
printf("Waiting for locks (attempt %d/%d)...\n",
attempt + 1, maxAttempts);
free(result);
}
}
if (attempt < maxAttempts - 1) { // Don't sleep on the last attempt
#ifdef _WIN32
Sleep(waitInterval);
#else
usleep(waitInterval * 1000);
#endif
}
}
printf("Timed out waiting for apt locks\n");
return false;
}
/*
* Function to update system and log the process
*/
static bool updateSystem(VixHandle vmHandle) {
VixError err;
VixHandle jobHandle;
char* result = NULL;
bool success = true;
printf("Starting system update process...\n");
// Проверяем запущенные процессы apt и dpkg
result = runCommandAndGetOutput(vmHandle,
"/bin/bash",
"-c 'if pidof apt apt-get dpkg > /dev/null; then echo \"BUSY\"; else echo \"FREE\"; fi'");
if (!result || strstr(result, "BUSY")) {
printf("Package management system is busy. Please wait for other package operations to complete.\n");
free(result);
return false;
}
free(result);
// Проверяем наличие блокировок
result = runCommandAndGetOutput(vmHandle,
"/bin/bash",
"-c 'if [ -f /var/lib/dpkg/lock ] || [ -f /var/lib/apt/lists/lock ] || [ -f /var/lib/dpkg/lock-frontend ]; then echo \"LOCKED\"; else echo \"UNLOCKED\"; fi'");
if (!result || strstr(result, "LOCKED")) {
printf("Package system is locked. Attempting to clean up...\n");
free(result);
// Пробуем удалить блокировки
result = executeSudoCommand(vmHandle,
"rm -f /var/lib/apt/lists/lock /var/cache/apt/archives/lock /var/lib/dpkg/lock* 2>/dev/null || true");
free(result);
} else {
free(result);
}
// Update package lists
result = executeSudoCommand(vmHandle,
"DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get update -y");
if (result) {
printf("Package lists update output:\n%s\n", result);
free(result);
} else {
printf("Failed to update package lists\n");
success = false;
}
if (!success) return false;
// Upgrade packages
result = executeSudoCommand(vmHandle,
"DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get upgrade -y");
if (result) {
printf("System upgrade output:\n%s\n", result);
free(result);
} else {
printf("Failed to upgrade system\n");
success = false;
}
if (!success) return false;
// Clean up
result = executeSudoCommand(vmHandle,
"DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get clean");
if (result) {
printf("Cleanup output:\n%s\n", result);
free(result);
}
// Print current system status
result = executeSudoCommand(vmHandle,
"DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get update -qq");
if (result) {
printf("Final system status:\n%s\n", result);
free(result);
}
return success;
}
/*
* Function to check system prerequisites
*/
static bool checkPrerequisites(VixHandle vmHandle) {
char* result = NULL;
bool success = true;
printf("Checking system prerequisites...\n");
// Check sudo access
result = runCommandAndGetOutput(vmHandle,
"/bin/bash",
"-c '/usr/bin/sudo -n true | tee /tmp/command_output.txt 2>&1'");
if (result) {
printf("Sudo access check: %s\n", result);
free(result);
}
// Check apt-get exists
result = runCommandAndGetOutput(vmHandle,
"/bin/bash",
"-c '/bin/ls -l /usr/bin/apt-get | tee /tmp/command_output.txt'");
if (result) {
printf("apt-get check: %s\n", result);
free(result);
}
// Check network connectivity
result = runCommandAndGetOutput(vmHandle,
"/bin/bash",
"-c '/bin/ping -c 1 8.8.8.8 | tee /tmp/command_output.txt'");
if (result) {
printf("Network check: %s\n", result);
free(result);
}
return success;
}
/*
* Function to check internet connectivity
*/
static bool checkInternetConnection(VixHandle vmHandle) {
char* result = NULL;
bool hasConnection = false;
printf("Checking internet connection...\n");
// Try to ping Google DNS server
result = runCommandAndGetOutput(vmHandle,
"/bin/bash",
"-c 'ping -c 3 8.8.8.8 > /tmp/command_output.txt 2>&1'");
if (result) {
if (strstr(result, "bytes from 8.8.8.8") != NULL) {
printf("Internet connection is available (ping successful)\n");
hasConnection = true;
} else {
printf("No internet connection (ping failed)\n");
}
free(result);
}
// If ping failed, try DNS resolution as backup check
if (!hasConnection) {
result = runCommandAndGetOutput(vmHandle,
"/bin/bash",
"-c 'nslookup google.com > /tmp/command_output.txt 2>&1'");
if (result) {
if (strstr(result, "Address:") != NULL) {
printf("Internet connection is available (DNS resolution successful)\n");
hasConnection = true;
} else {
printf("No internet connection (DNS resolution failed)\n");
}
free(result);
}
}
return hasConnection;
}
/*
* Function to check internet speed using speedtest-cli
*/
static bool checkInternetSpeed(VixHandle vmHandle) {
char* result = NULL;
bool success = false;
printf("Checking internet speed...\n");
// First, check if speedtest-cli is installed
result = runCommandAndGetOutput(vmHandle,
"/bin/bash",
"-c 'which speedtest-cli > /tmp/command_output.txt 2>&1'");
if (!result || strstr(result, "speedtest-cli") == NULL) {
printf("speedtest-cli not found. Installing...\n");
free(result);
// Update package list first
result = executeSudoCommand(vmHandle,
"apt-get update");
free(result);
// Try installing directly from repository
result = executeSudoCommand(vmHandle,
"DEBIAN_FRONTEND=noninteractive apt-get install -y speedtest-cli");
if (result) {
printf("Installation output: %s\n", result);
free(result);
}
// Verify installation again
result = runCommandAndGetOutput(vmHandle,
"/bin/bash",
"-c 'which speedtest-cli > /tmp/command_output.txt 2>&1'");
if (!result || strstr(result, "speedtest-cli") == NULL) {
printf("Failed to install speedtest-cli from repository, trying alternative method...\n");
free(result);
// Try installing using snap as alternative
result = executeSudoCommand(vmHandle,
"snap install speedtest-cli");
if (result) {
printf("Snap installation output: %s\n", result);
free(result);
}
// Final verification
result = runCommandAndGetOutput(vmHandle,
"/bin/bash",
"-c 'which speedtest-cli > /tmp/command_output.txt 2>&1'");
if (!result || strstr(result, "speedtest-cli") == NULL) {
printf("All installation methods failed\n");
free(result);
return false;
}
}
free(result);
} else {
free(result);
}
printf("Running speed test (this may take a minute)...\n");
// Run speedtest with simple output format
result = runCommandAndGetOutput(vmHandle,
"/bin/bash",
"-c 'speedtest-cli --simple > /tmp/command_output.txt 2>&1'");
if (result) {
if (strstr(result, "Ping:") != NULL) {
printf("\nSpeed test results:\n%s", result);
success = true;
} else {
printf("Speed test failed. Error output:\n%s\n", result);
}
free(result);
} else {
printf("Failed to run speed test\n");
}
return success;
}
/*
* Function to install and configure nginx
*/
static bool setupNginx(VixHandle vmHandle) {
char* result = NULL;
bool success = true;
char command_buffer[4096];
printf("Setting up nginx server...\n");
// Check if nginx is already installed
result = runCommandAndGetOutput(vmHandle,
"/bin/bash",
"-c 'which nginx > /tmp/command_output.txt 2>&1'");
if (!result || strstr(result, "nginx") == NULL) {
printf("nginx not found. Installing...\n");
free(result);
// Update package list
result = executeSudoCommand(vmHandle, "apt-get update");
free(result);
// Install nginx
result = executeSudoCommand(vmHandle,
"DEBIAN_FRONTEND=noninteractive apt-get install -y nginx");
free(result);
} else {
free(result);
}
// Создаем простой скрипт настройки
snprintf(command_buffer, sizeof(command_buffer),
"bash -c '\n"
"# Остановка nginx\n"
"sudo systemctl stop nginx\n"
"sleep 2\n"
"\n"
"# Создание HTML страницы\n"
"sudo tee /var/www/html/index.html > /dev/null << EOF\n"
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
" <title>Hello World</title>\n"
"</head>\n"
"<body>\n"
" <h1>Hello World!</h1>\n"
"</body>\n"
"</html>\n"
"EOF\n"
"\n"
"# Настройка прав доступа\n"
"sudo chown -R www-data:www-data /var/www/html\n"
"sudo chmod -R 755 /var/www/html\n"
"\n"
"# Создание конфигурации nginx\n"
"sudo tee /etc/nginx/sites-available/default > /dev/null << EOF\n"
"server {\n"
" listen 80 default_server;\n"
" listen [::]:80 default_server;\n"
" root /var/www/html;\n"
" index index.html;\n"
" server_name _;\n"
" location / {\n"
" try_files \\$uri \\$uri/ =404;\n"
" }\n"
"}\n"
"EOF\n"
"\n"
"# Проверка конфигурации\n"
"sudo nginx -t\n"
"\n"
"# Запуск nginx\n"
"sudo systemctl start nginx\n"
"sleep 2\n"
"\n"
"# Проверка статуса\n"
"sudo systemctl status nginx\n"
"'");
// Выполняем скрипт настройки
result = executeSudoCommand(vmHandle, command_buffer);
if (result) {
printf("Setup script output:\n%s\n", result);
free(result);
}
// Проверяем, что nginx запущен
result = executeSudoCommand(vmHandle, "systemctl is-active nginx");
if (!result || strstr(result, "active") == NULL) {
printf("Nginx is not running\n");
free(result);
return false;
}
free(result);
// Проверяем содержимое страницы
result = executeSudoCommand(vmHandle, "curl -s http://localhost");
if (result) {
if (strstr(result, "Hello World") != NULL) {
printf("Successfully verified Hello World page is accessible\n");
success = true;
} else {
printf("Page content verification failed. Got:\n%s\n", result);
success = false;
}
free(result);
}
// Get IP address
result = runCommandAndGetOutput(vmHandle,
"/bin/bash",
"-c 'hostname -I | awk \"{print \\$1}\" > /tmp/command_output.txt'");
if (result) {
printf("\nNginx server is running!\n");
printf("You can access the Hello World page at: http://%s\n", result);
free(result);
}
return success;
}
int main(int argc, char** argv) {
VixError err;
VixHandle hostHandle = VIX_INVALID_HANDLE;
VixHandle jobHandle = VIX_INVALID_HANDLE;
VixHandle vmHandle = VIX_INVALID_HANDLE;
char* sysInfo = NULL;
char* currentDir = NULL;
// Connect to VMware
jobHandle = VixHost_Connect(VIX_API_VERSION,
CONNTYPE,
HOSTNAME,
HOSTPORT,
USERNAME,
PASSWORD,
0,
VIX_INVALID_HANDLE,
NULL,
NULL);
err = VixJob_Wait(jobHandle,
VIX_PROPERTY_JOB_RESULT_HANDLE,
&hostHandle,
VIX_PROPERTY_NONE);
Vix_ReleaseHandle(jobHandle);
if (VIX_FAILED(err)) {
handleVixError(err, "Connecting to host");
goto abort;
}
printf("Connected to VMware host\n");
// Open VM
jobHandle = VixHost_OpenVM(hostHandle,
VMX_PATH,
VIX_VMOPEN_NORMAL,
VIX_INVALID_HANDLE,
NULL,
NULL);
err = VixJob_Wait(jobHandle,
VIX_PROPERTY_JOB_RESULT_HANDLE,
&vmHandle,
VIX_PROPERTY_NONE);
Vix_ReleaseHandle(jobHandle);
if (VIX_FAILED(err)) {
handleVixError(err, "Opening VM");
goto abort;
}
printf("Opened VM: %s\n", VMX_PATH);
// Wait for Tools
jobHandle = VixVM_WaitForToolsInGuest(vmHandle,
TOOLS_TIMEOUT,
NULL,
NULL);
err = VixJob_Wait(jobHandle, VIX_PROPERTY_NONE);
Vix_ReleaseHandle(jobHandle);
if (VIX_FAILED(err)) {
handleVixError(err, "Waiting for VMware Tools");
goto abort;
}
printf("VMware Tools are running\n");
// Login to guest
jobHandle = VixVM_LoginInGuest(vmHandle,
GUEST_USERNAME,
GUEST_PASSWORD,
0,
NULL,
NULL);
err = VixJob_Wait(jobHandle, VIX_PROPERTY_NONE);
Vix_ReleaseHandle(jobHandle);
if (VIX_FAILED(err)) {
handleVixError(err, "Login to guest");
goto abort;
}
printf("Logged in to guest\n");
// After successful login to guest, add:
if (checkInternetConnection(vmHandle)) {
if (checkPrerequisites(vmHandle)) {
if (setupNginx(vmHandle)) {
printf("Nginx setup completed successfully\n");
} else {
printf("Nginx setup failed\n");
}
} else {
printf("Prerequisites check failed\n");
}
} else {
printf("No internet connection available\n");
}
// Get system information
sysInfo = runCommandAndGetOutput(vmHandle,
"/bin/uname",
"-a > /tmp/command_output.txt");
if (sysInfo) {
printf("System information: %s", sysInfo);
} else {
printf("Failed to get system information\n");
}
// Get current directory
currentDir = runCommandAndGetOutput(vmHandle,
"/usr/bin/pwd",
"> /tmp/command_output.txt");
if (currentDir) {
printf("Current directory: %s", currentDir);
} else {
printf("Failed to get current directory\n");
}
abort:
if (vmHandle != VIX_INVALID_HANDLE) {
Vix_ReleaseHandle(vmHandle);
}
if (hostHandle != VIX_INVALID_HANDLE) {
VixHost_Disconnect(hostHandle);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment