Last active
February 3, 2025 20:18
-
-
Save CodeCouturiers/35299d14e2ddad6df6ab9e9d8dacf5ca to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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