linuxinstall/src/disk.c

252 lines
6.2 KiB
C
Raw Normal View History

#include "disk.h"
2024-02-17 23:59:38 +01:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
2024-02-18 14:56:36 +01:00
#include <libgen.h>
#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) {
// 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;
// Create the disk
int exit_code;
2024-02-17 23:59:38 +01:00
// char* stdout;
char* stderrb;
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 23:59:38 +01:00
free(size_str);
2024-02-17 23:59:38 +01:00
// Check if the disk was created successfully
if (status != SUCCESS)
return status;
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 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");
return FAILURE;
}
return SUCCESS;
}
2024-02-17 23:59:38 +01:00
Status CreateBackedDisk(const char* path, const char* backing_file) {
// Create the disk
int exit_code;
2024-02-17 23:59:38 +01:00
// char* stdout;
char* stderrb;
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 23:59:38 +01:00
// Check if the disk was created successfully
if (status != SUCCESS)
return status;
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 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");
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
int exit_code;
2024-02-17 23:59:38 +01:00
// char* stdout;
char* stderrb;
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 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");
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 23:59:38 +01:00
// Get the disk info
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);
return FAILURE;
}
2024-02-17 23:59:38 +01:00
free(stderrb);
// Parse the JSON output
2024-02-17 23:59:38 +01:00
json_object* root = json_tokener_parse(stdoutb);
free(stdoutb);
if (root == NULL) {
2024-02-17 23:59:38 +01:00
Log(LOG_LEVEL_ERROR, "Failed to parse the JSON output");
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 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 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));
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;
}
}
return SUCCESS;
}
2024-02-17 23:59:38 +01:00
void FreeDiskInfo(DiskInfo* info) {
free(info->backing_file);
2024-02-18 14:56:36 +01:00
free(info->backing_identifier);
}