2024-02-17 01:34:58 +01:00
|
|
|
#include "disk.h"
|
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
#include <stdio.h>
|
2024-02-17 01:34:58 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
2024-02-18 14:56:36 +01:00
|
|
|
#include <libgen.h>
|
2024-02-17 01:34:58 +01:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <json-c/json.h>
|
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
Status CreateRootDisk(const char* path, uint64_t disk_size) {
|
2024-02-17 01:34:58 +01:00
|
|
|
// Convert the size to a string
|
|
|
|
char* size_str;
|
2024-02-17 23:59:38 +01:00
|
|
|
Status status = Format(&size_str, "%lu", disk_size);
|
|
|
|
if (status != SUCCESS)
|
|
|
|
return status;
|
2024-02-17 01:34:58 +01:00
|
|
|
|
|
|
|
// Create the disk
|
|
|
|
int exit_code;
|
2024-02-17 23:59:38 +01:00
|
|
|
// char* stdout;
|
|
|
|
char* stderrb;
|
2024-02-17 01:34:58 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
status = RunExecutable(&exit_code, NULL, &stderrb, "/usr/bin/qemu-img", "create", "-f", "qcow2", path, size_str, NULL);
|
2024-02-17 01:34:58 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
free(size_str);
|
2024-02-17 01:34:58 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
// Check if the disk was created successfully
|
|
|
|
if (status != SUCCESS)
|
|
|
|
return status;
|
2024-02-17 01:34:58 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
if (exit_code != 0) {
|
|
|
|
if (stderrb != NULL) {
|
|
|
|
// Remove newlines from the stderr buffer
|
|
|
|
for (int i = 0; stderrb[i] != '\0'; i++)
|
|
|
|
if (stderrb[i] == '\n')
|
|
|
|
stderrb[i] = ' ';
|
2024-02-17 01:34:58 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
Log(LOG_LEVEL_ERROR, "Failed to create disk at '%s' (%s).", path, stderrb);
|
|
|
|
free(stderrb);
|
|
|
|
} else
|
|
|
|
Log(LOG_LEVEL_ERROR, "Failed to create disk");
|
2024-02-17 01:34:58 +01:00
|
|
|
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
Status CreateBackedDisk(const char* path, const char* backing_file) {
|
2024-02-17 01:34:58 +01:00
|
|
|
// Create the disk
|
|
|
|
int exit_code;
|
2024-02-17 23:59:38 +01:00
|
|
|
// char* stdout;
|
|
|
|
char* stderrb;
|
2024-02-17 01:34:58 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
Status status = RunExecutable(&exit_code, NULL, &stderrb, "/usr/bin/qemu-img", "create", "-f", "qcow2", "-F", "qcow2", "-b", backing_file, path, NULL);
|
2024-02-17 01:34:58 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
// Check if the disk was created successfully
|
|
|
|
if (status != SUCCESS)
|
|
|
|
return status;
|
2024-02-17 01:34:58 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
if (exit_code != 0) {
|
|
|
|
if (stderrb != NULL) {
|
|
|
|
// Remove newlines from the stderr buffer
|
|
|
|
for (int i = 0; stderrb[i] != '\0'; i++)
|
|
|
|
if (stderrb[i] == '\n')
|
|
|
|
stderrb[i] = ' ';
|
2024-02-17 01:34:58 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
Log(LOG_LEVEL_ERROR, "Failed to create disk at '%s' (%s).", path, stderrb);
|
|
|
|
free(stderrb);
|
|
|
|
} else
|
|
|
|
Log(LOG_LEVEL_ERROR, "Failed to create disk");
|
2024-02-17 01:34:58 +01:00
|
|
|
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
Status TrimDisk(const char* path) {
|
|
|
|
char* tmp_path = NULL;
|
|
|
|
Status status = Format(&tmp_path, "%s.tmp", path);
|
|
|
|
if (status != SUCCESS)
|
|
|
|
return status;
|
2024-02-17 02:39:41 +01:00
|
|
|
|
|
|
|
DiskInfo info;
|
2024-02-17 23:59:38 +01:00
|
|
|
status = GetDiskInfo(path, &info);
|
|
|
|
if (status != SUCCESS) {
|
2024-02-17 02:39:41 +01:00
|
|
|
free(tmp_path);
|
2024-02-17 23:59:38 +01:00
|
|
|
return status;
|
2024-02-17 02:39:41 +01:00
|
|
|
}
|
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
// Create the temporary disk
|
2024-02-17 02:39:41 +01:00
|
|
|
int exit_code;
|
2024-02-17 23:59:38 +01:00
|
|
|
// char* stdout;
|
|
|
|
char* stderrb;
|
|
|
|
|
|
|
|
if (info.backing_file != NULL) {
|
|
|
|
char* backing_file_opt = NULL;
|
|
|
|
status = Format(&backing_file_opt, "backing_file=%s", info.backing_file);
|
|
|
|
if (status != SUCCESS) {
|
2024-02-17 02:39:41 +01:00
|
|
|
free(tmp_path);
|
2024-02-17 23:59:38 +01:00
|
|
|
FreeDiskInfo(&info);
|
|
|
|
return status;
|
2024-02-17 02:39:41 +01:00
|
|
|
}
|
|
|
|
|
2024-02-18 14:05:04 +01:00
|
|
|
status = RunExecutable(&exit_code, NULL, &stderrb, "/usr/bin/qemu-img", "convert", "-f", "qcow2", "-F", "qcow2", "-O", "qcow2", "-o", backing_file_opt, path, tmp_path, NULL);
|
2024-02-17 02:39:41 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
free(backing_file_opt);
|
|
|
|
} else
|
2024-02-18 14:05:04 +01:00
|
|
|
status = RunExecutable(&exit_code, NULL, &stderrb, "/usr/bin/qemu-img", "convert", "-f", "qcow2", "-O", "qcow2", path, tmp_path, NULL);
|
2024-02-17 02:39:41 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
FreeDiskInfo(&info);
|
2024-02-17 02:39:41 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
// Check if the disk was created successfully
|
|
|
|
if (status != SUCCESS) {
|
2024-02-17 02:39:41 +01:00
|
|
|
free(tmp_path);
|
2024-02-17 23:59:38 +01:00
|
|
|
return status;
|
2024-02-17 02:39:41 +01:00
|
|
|
}
|
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
if (exit_code != 0) {
|
|
|
|
if (stderrb != NULL) {
|
|
|
|
// Remove newlines from the stderr buffer
|
|
|
|
for (int i = 0; stderrb[i] != '\0'; i++)
|
|
|
|
if (stderrb[i] == '\n')
|
|
|
|
stderrb[i] = ' ';
|
|
|
|
|
|
|
|
Log(LOG_LEVEL_ERROR, "Failed to create temporary disk at '%s' (%s).", tmp_path, stderrb);
|
|
|
|
free(stderrb);
|
|
|
|
} else
|
|
|
|
Log(LOG_LEVEL_ERROR, "Failed to create temporary disk");
|
2024-02-17 02:39:41 +01:00
|
|
|
|
|
|
|
free(tmp_path);
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
// Try to move the temporary disk to the original path
|
2024-02-17 02:39:41 +01:00
|
|
|
if (rename(tmp_path, path) != 0) {
|
2024-02-17 23:59:38 +01:00
|
|
|
Log(LOG_LEVEL_ERROR, "Failed to move the temporary disk to the original path '%s' (%s).", path, strerror(errno));
|
2024-02-17 02:39:41 +01:00
|
|
|
|
|
|
|
unlink(tmp_path);
|
2024-02-17 23:59:38 +01:00
|
|
|
|
2024-02-17 02:39:41 +01:00
|
|
|
free(tmp_path);
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(tmp_path);
|
2024-02-17 23:59:38 +01:00
|
|
|
|
2024-02-17 02:39:41 +01:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
Status RebaseDisk(const char* path, const char* backing_file) {
|
|
|
|
// Create the disk
|
2024-02-17 01:34:58 +01:00
|
|
|
int exit_code;
|
2024-02-17 23:59:38 +01:00
|
|
|
// char* stdout;
|
|
|
|
char* stderrb;
|
2024-02-17 01:34:58 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
Status status = RunExecutable(&exit_code, NULL, &stderrb, "/usr/bin/qemu-img", "rebase", "-u", "-b", backing_file, path, NULL);
|
2024-02-17 01:34:58 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
// Check if the disk was created successfully
|
|
|
|
if (status != SUCCESS)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
if (exit_code != 0) {
|
|
|
|
if (stderrb != NULL) {
|
|
|
|
// Remove newlines from the stderr buffer
|
|
|
|
for (int i = 0; stderrb[i] != '\0'; i++)
|
|
|
|
if (stderrb[i] == '\n')
|
|
|
|
stderrb[i] = ' ';
|
|
|
|
|
|
|
|
Log(LOG_LEVEL_ERROR, "Failed to rebase disk at '%s' (%s).", path, stderrb);
|
|
|
|
free(stderrb);
|
|
|
|
} else
|
|
|
|
Log(LOG_LEVEL_ERROR, "Failed to rebase disk");
|
2024-02-17 01:34:58 +01:00
|
|
|
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
Status GetDiskInfo(const char* path, DiskInfo* _info) {
|
|
|
|
*_info = (DiskInfo){0};
|
2024-02-17 01:34:58 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
// Get the disk info
|
2024-02-17 01:34:58 +01:00
|
|
|
int exit_code;
|
2024-02-17 23:59:38 +01:00
|
|
|
char* stdoutb;
|
|
|
|
char* stderrb;
|
|
|
|
|
|
|
|
Status status = RunExecutable(&exit_code, &stdoutb, &stderrb, "/usr/bin/qemu-img", "info", "--output", "json", path, NULL);
|
|
|
|
if (status != SUCCESS)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
if (exit_code != 0) {
|
|
|
|
if (stderrb != NULL) {
|
|
|
|
// Remove newlines from the stderr buffer
|
|
|
|
for (int i = 0; stderrb[i] != '\0'; i++)
|
|
|
|
if (stderrb[i] == '\n')
|
|
|
|
stderrb[i] = ' ';
|
|
|
|
|
|
|
|
Log(LOG_LEVEL_ERROR, "Failed to get disk info at '%s' (%s).", path, stderrb);
|
|
|
|
free(stderrb);
|
|
|
|
} else
|
|
|
|
Log(LOG_LEVEL_ERROR, "Failed to get disk info");
|
|
|
|
|
|
|
|
free(stdoutb);
|
2024-02-17 01:34:58 +01:00
|
|
|
return FAILURE;
|
|
|
|
}
|
2024-02-17 23:59:38 +01:00
|
|
|
free(stderrb);
|
2024-02-17 02:46:21 +01:00
|
|
|
|
2024-02-17 01:34:58 +01:00
|
|
|
// Parse the JSON output
|
2024-02-17 23:59:38 +01:00
|
|
|
json_object* root = json_tokener_parse(stdoutb);
|
|
|
|
free(stdoutb);
|
|
|
|
|
2024-02-17 01:34:58 +01:00
|
|
|
if (root == NULL) {
|
2024-02-17 23:59:38 +01:00
|
|
|
Log(LOG_LEVEL_ERROR, "Failed to parse the JSON output");
|
2024-02-17 01:34:58 +01:00
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
json_object* virtual_size = NULL;
|
|
|
|
json_object* actual_size = NULL;
|
|
|
|
json_object* backing_file = NULL;
|
2024-02-17 01:34:58 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
json_object_object_get_ex(root, "virtual-size", &virtual_size);
|
|
|
|
json_object_object_get_ex(root, "actual-size", &actual_size);
|
|
|
|
json_object_object_get_ex(root, "backing-filename", &backing_file);
|
2024-02-17 01:34:58 +01:00
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
if (virtual_size != NULL)
|
|
|
|
_info->size = json_object_get_int64(virtual_size);
|
|
|
|
if (actual_size != NULL)
|
|
|
|
_info->allocated = json_object_get_int64(actual_size);
|
|
|
|
if (backing_file != NULL)
|
|
|
|
_info->backing_file = strdup(json_object_get_string(backing_file));
|
2024-02-17 01:34:58 +01:00
|
|
|
|
|
|
|
json_object_put(root);
|
|
|
|
|
2024-02-18 14:56:36 +01:00
|
|
|
if (_info->backing_file != NULL) {
|
|
|
|
_info->backing_identifier = strdup(basename(_info->backing_file));
|
|
|
|
if (_info->backing_identifier == NULL) {
|
|
|
|
Log(LOG_LEVEL_ERROR, "Failed to duplicate the backing identifier (%s).", strerror(errno));
|
|
|
|
FreeDiskInfo(_info);
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-17 01:34:58 +01:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
2024-02-17 23:59:38 +01:00
|
|
|
void FreeDiskInfo(DiskInfo* info) {
|
2024-02-17 01:34:58 +01:00
|
|
|
free(info->backing_file);
|
2024-02-18 14:56:36 +01:00
|
|
|
free(info->backing_identifier);
|
|
|
|
}
|