mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-26 18:41:17 +00:00
Move generic file & I/O routines out of QEMU driver into util.c
This commit is contained in:
parent
ed5e20baab
commit
4cd62fe306
10
ChangeLog
10
ChangeLog
@ -1,3 +1,13 @@
|
|||||||
|
Mon Dec 3 9:10:10 EST 2007 Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
|
||||||
|
* src/qemu_conf.c: remove qemudMakeConfigPath, qemudEnsureDir,
|
||||||
|
qemudReadFile,compareFileToNameSuffix, hasSuffix, checkLinkPointsTo
|
||||||
|
* src/qemu_conf.h: remove qemudEnsureDir
|
||||||
|
* src/qemu_driver.c: Update to use new API names
|
||||||
|
* src/util.h, src/util.c: add virFileReadAll, virFileHasSuffix,
|
||||||
|
virFileMatchsNameSuffix, virFileLinkPointsTo, virFileMakePath,
|
||||||
|
virFileBuildPath
|
||||||
|
|
||||||
Mon Dec 3 10:32:10 CET 2007 Daniel Veillard <veillard@redhat.com>
|
Mon Dec 3 10:32:10 CET 2007 Daniel Veillard <veillard@redhat.com>
|
||||||
|
|
||||||
* src/xen_unified.[ch] src/proxy_internal.c src/xen_internal.c
|
* src/xen_unified.[ch] src/proxy_internal.c src/xen_internal.c
|
||||||
|
256
src/qemu_conf.c
256
src/qemu_conf.c
@ -48,6 +48,7 @@
|
|||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
#include "buf.h"
|
#include "buf.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#define qemudLog(level, msg...) fprintf(stderr, msg)
|
#define qemudLog(level, msg...) fprintf(stderr, msg)
|
||||||
|
|
||||||
@ -227,55 +228,6 @@ void qemudFreeVM(struct qemud_vm *vm) {
|
|||||||
free(vm);
|
free(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build up a fully qualfiied path for a config file to be
|
|
||||||
* associated with a persistent guest or network */
|
|
||||||
static int
|
|
||||||
qemudMakeConfigPath(const char *configDir,
|
|
||||||
const char *name,
|
|
||||||
const char *ext,
|
|
||||||
char *buf,
|
|
||||||
unsigned int buflen) {
|
|
||||||
if ((strlen(configDir) + 1 + strlen(name) + (ext ? strlen(ext) : 0) + 1) > buflen)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
strcpy(buf, configDir);
|
|
||||||
strcat(buf, "/");
|
|
||||||
strcat(buf, name);
|
|
||||||
if (ext)
|
|
||||||
strcat(buf, ext);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
qemudEnsureDir(const char *path)
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
char parent[PATH_MAX];
|
|
||||||
char *p;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (stat(path, &st) >= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
strncpy(parent, path, PATH_MAX);
|
|
||||||
parent[PATH_MAX - 1] = '\0';
|
|
||||||
|
|
||||||
if (!(p = strrchr(parent, '/')))
|
|
||||||
return EINVAL;
|
|
||||||
|
|
||||||
if (p == parent)
|
|
||||||
return EPERM;
|
|
||||||
|
|
||||||
*p = '\0';
|
|
||||||
|
|
||||||
if ((err = qemudEnsureDir(parent)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (mkdir(path, 0777) < 0 && errno != EEXIST)
|
|
||||||
return errno;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The list of possible machine types for various architectures,
|
/* The list of possible machine types for various architectures,
|
||||||
as supported by QEMU - taken from 'qemu -M ?' for each arch */
|
as supported by QEMU - taken from 'qemu -M ?' for each arch */
|
||||||
@ -2075,22 +2027,22 @@ qemudSaveVMDef(virConnectPtr conn,
|
|||||||
if (vm->configFile[0] == '\0') {
|
if (vm->configFile[0] == '\0') {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if ((err = qemudEnsureDir(driver->configDir))) {
|
if ((err = virFileMakePath(driver->configDir))) {
|
||||||
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
"cannot create config directory %s: %s",
|
"cannot create config directory %s: %s",
|
||||||
driver->configDir, strerror(err));
|
driver->configDir, strerror(err));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemudMakeConfigPath(driver->configDir, def->name, ".xml",
|
if (virFileBuildPath(driver->configDir, def->name, ".xml",
|
||||||
vm->configFile, PATH_MAX) < 0) {
|
vm->configFile, PATH_MAX) < 0) {
|
||||||
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
"cannot construct config file path");
|
"cannot construct config file path");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemudMakeConfigPath(driver->autostartDir, def->name, ".xml",
|
if (virFileBuildPath(driver->autostartDir, def->name, ".xml",
|
||||||
vm->autostartLink, PATH_MAX) < 0) {
|
vm->autostartLink, PATH_MAX) < 0) {
|
||||||
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
"cannot construct autostart link path");
|
"cannot construct autostart link path");
|
||||||
vm->configFile[0] = '\0';
|
vm->configFile[0] = '\0';
|
||||||
@ -2114,7 +2066,7 @@ static int qemudSaveNetworkConfig(virConnectPtr conn,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = qemudEnsureDir(driver->networkConfigDir))) {
|
if ((err = virFileMakePath(driver->networkConfigDir))) {
|
||||||
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
"cannot create config directory %s: %s",
|
"cannot create config directory %s: %s",
|
||||||
driver->networkConfigDir, strerror(err));
|
driver->networkConfigDir, strerror(err));
|
||||||
@ -2521,22 +2473,22 @@ qemudSaveNetworkDef(virConnectPtr conn,
|
|||||||
if (network->configFile[0] == '\0') {
|
if (network->configFile[0] == '\0') {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if ((err = qemudEnsureDir(driver->networkConfigDir))) {
|
if ((err = virFileMakePath(driver->networkConfigDir))) {
|
||||||
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
"cannot create config directory %s: %s",
|
"cannot create config directory %s: %s",
|
||||||
driver->networkConfigDir, strerror(err));
|
driver->networkConfigDir, strerror(err));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemudMakeConfigPath(driver->networkConfigDir, def->name, ".xml",
|
if (virFileBuildPath(driver->networkConfigDir, def->name, ".xml",
|
||||||
network->configFile, PATH_MAX) < 0) {
|
network->configFile, PATH_MAX) < 0) {
|
||||||
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
"cannot construct config file path");
|
"cannot construct config file path");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemudMakeConfigPath(driver->networkAutostartDir, def->name, ".xml",
|
if (virFileBuildPath(driver->networkAutostartDir, def->name, ".xml",
|
||||||
network->autostartLink, PATH_MAX) < 0) {
|
network->autostartLink, PATH_MAX) < 0) {
|
||||||
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
"cannot construct autostart link path");
|
"cannot construct autostart link path");
|
||||||
network->configFile[0] = '\0';
|
network->configFile[0] = '\0';
|
||||||
@ -2547,174 +2499,6 @@ qemudSaveNetworkDef(virConnectPtr conn,
|
|||||||
return qemudSaveNetworkConfig(conn, driver, network, def);
|
return qemudSaveNetworkConfig(conn, driver, network, def);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
qemudReadFile(const char *path,
|
|
||||||
char *buf,
|
|
||||||
int maxlen) {
|
|
||||||
FILE *fh;
|
|
||||||
struct stat st;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (!(fh = fopen(path, "r"))) {
|
|
||||||
qemudLog(QEMUD_WARN, "Failed to open file '%s': %s",
|
|
||||||
path, strerror(errno));
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fstat(fileno(fh), &st) < 0) {
|
|
||||||
qemudLog(QEMUD_WARN, "Failed to stat file '%s': %s",
|
|
||||||
path, strerror(errno));
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
|
||||||
qemudDebug("Ignoring directory '%s' - clearly not a config file", path);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (st.st_size >= maxlen) {
|
|
||||||
qemudLog(QEMUD_WARN, "File '%s' is too large", path);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret = fread(buf, st.st_size, 1, fh)) != 1) {
|
|
||||||
qemudLog(QEMUD_WARN, "Failed to read config file '%s': %s",
|
|
||||||
path, strerror(errno));
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[st.st_size] = '\0';
|
|
||||||
|
|
||||||
ret = 1;
|
|
||||||
|
|
||||||
error:
|
|
||||||
if (fh)
|
|
||||||
fclose(fh);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
compareFileToNameSuffix(const char *file,
|
|
||||||
const char *name,
|
|
||||||
const char *suffix) {
|
|
||||||
int filelen = strlen(file);
|
|
||||||
int namelen = strlen(name);
|
|
||||||
int suffixlen = strlen(suffix);
|
|
||||||
|
|
||||||
if (filelen == (namelen + suffixlen) &&
|
|
||||||
!strncmp(file, name, namelen) &&
|
|
||||||
!strncmp(file + namelen, suffix, suffixlen))
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
hasSuffix(const char *str,
|
|
||||||
const char *suffix)
|
|
||||||
{
|
|
||||||
int len = strlen(str);
|
|
||||||
int suffixlen = strlen(suffix);
|
|
||||||
|
|
||||||
if (len < suffixlen)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return strcmp(str + len - suffixlen, suffix) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
checkLinkPointsTo(const char *checkLink,
|
|
||||||
const char *checkDest)
|
|
||||||
{
|
|
||||||
char dest[PATH_MAX];
|
|
||||||
char real[PATH_MAX];
|
|
||||||
char checkReal[PATH_MAX];
|
|
||||||
int n;
|
|
||||||
int passed = 0;
|
|
||||||
|
|
||||||
/* read the link destination */
|
|
||||||
if ((n = readlink(checkLink, dest, PATH_MAX)) < 0) {
|
|
||||||
switch (errno) {
|
|
||||||
case ENOENT:
|
|
||||||
case ENOTDIR:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EINVAL:
|
|
||||||
qemudLog(QEMUD_WARN, "Autostart file '%s' is not a symlink",
|
|
||||||
checkLink);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
qemudLog(QEMUD_WARN, "Failed to read autostart symlink '%s': %s",
|
|
||||||
checkLink, strerror(errno));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
goto failed;
|
|
||||||
} else if (n >= PATH_MAX) {
|
|
||||||
qemudLog(QEMUD_WARN, "Symlink '%s' contents too long to fit in buffer",
|
|
||||||
checkLink);
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
dest[n] = '\0';
|
|
||||||
|
|
||||||
/* make absolute */
|
|
||||||
if (dest[0] != '/') {
|
|
||||||
char dir[PATH_MAX];
|
|
||||||
char tmp[PATH_MAX];
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
strncpy(dir, checkLink, PATH_MAX);
|
|
||||||
dir[PATH_MAX-1] = '\0';
|
|
||||||
|
|
||||||
if (!(p = strrchr(dir, '/'))) {
|
|
||||||
qemudLog(QEMUD_WARN, "Symlink path '%s' is not absolute", checkLink);
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p == dir) /* handle unlikely root dir case */
|
|
||||||
p++;
|
|
||||||
|
|
||||||
*p = '\0';
|
|
||||||
|
|
||||||
if (qemudMakeConfigPath(dir, dest, NULL, tmp, PATH_MAX) < 0) {
|
|
||||||
qemudLog(QEMUD_WARN, "Path '%s/%s' is too long", dir, dest);
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(dest, tmp, PATH_MAX);
|
|
||||||
dest[PATH_MAX-1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* canonicalize both paths */
|
|
||||||
if (!realpath(dest, real)) {
|
|
||||||
qemudLog(QEMUD_WARN, "Failed to expand path '%s' :%s",
|
|
||||||
dest, strerror(errno));
|
|
||||||
strncpy(real, dest, PATH_MAX);
|
|
||||||
real[PATH_MAX-1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!realpath(checkDest, checkReal)) {
|
|
||||||
qemudLog(QEMUD_WARN, "Failed to expand path '%s' :%s",
|
|
||||||
checkDest, strerror(errno));
|
|
||||||
strncpy(checkReal, checkDest, PATH_MAX);
|
|
||||||
checkReal[PATH_MAX-1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* compare */
|
|
||||||
if (strcmp(checkReal, real) != 0) {
|
|
||||||
qemudLog(QEMUD_WARN, "Autostart link '%s' is not a symlink to '%s', ignoring",
|
|
||||||
checkLink, checkReal);
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
passed = 1;
|
|
||||||
|
|
||||||
failed:
|
|
||||||
return passed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct qemud_vm *
|
static struct qemud_vm *
|
||||||
qemudLoadConfig(struct qemud_driver *driver,
|
qemudLoadConfig(struct qemud_driver *driver,
|
||||||
@ -2732,7 +2516,7 @@ qemudLoadConfig(struct qemud_driver *driver,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!compareFileToNameSuffix(file, def->name, ".xml")) {
|
if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
|
||||||
qemudLog(QEMUD_WARN, "QEMU guest config filename '%s' does not match guest name '%s'",
|
qemudLog(QEMUD_WARN, "QEMU guest config filename '%s' does not match guest name '%s'",
|
||||||
path, def->name);
|
path, def->name);
|
||||||
qemudFreeVMDef(def);
|
qemudFreeVMDef(def);
|
||||||
@ -2751,7 +2535,7 @@ qemudLoadConfig(struct qemud_driver *driver,
|
|||||||
strncpy(vm->autostartLink, autostartLink, PATH_MAX);
|
strncpy(vm->autostartLink, autostartLink, PATH_MAX);
|
||||||
vm->autostartLink[PATH_MAX-1] = '\0';
|
vm->autostartLink[PATH_MAX-1] = '\0';
|
||||||
|
|
||||||
vm->autostart = checkLinkPointsTo(vm->autostartLink, vm->configFile);
|
vm->autostart = virFileLinkPointsTo(vm->autostartLink, vm->configFile);
|
||||||
|
|
||||||
return vm;
|
return vm;
|
||||||
}
|
}
|
||||||
@ -2772,7 +2556,7 @@ qemudLoadNetworkConfig(struct qemud_driver *driver,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!compareFileToNameSuffix(file, def->name, ".xml")) {
|
if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
|
||||||
qemudLog(QEMUD_WARN, "Network config filename '%s' does not match network name '%s'",
|
qemudLog(QEMUD_WARN, "Network config filename '%s' does not match network name '%s'",
|
||||||
path, def->name);
|
path, def->name);
|
||||||
qemudFreeNetworkDef(def);
|
qemudFreeNetworkDef(def);
|
||||||
@ -2791,7 +2575,7 @@ qemudLoadNetworkConfig(struct qemud_driver *driver,
|
|||||||
strncpy(network->autostartLink, autostartLink, PATH_MAX);
|
strncpy(network->autostartLink, autostartLink, PATH_MAX);
|
||||||
network->autostartLink[PATH_MAX-1] = '\0';
|
network->autostartLink[PATH_MAX-1] = '\0';
|
||||||
|
|
||||||
network->autostart = checkLinkPointsTo(network->autostartLink, network->configFile);
|
network->autostart = virFileLinkPointsTo(network->autostartLink, network->configFile);
|
||||||
|
|
||||||
return network;
|
return network;
|
||||||
}
|
}
|
||||||
@ -2820,22 +2604,22 @@ int qemudScanConfigDir(struct qemud_driver *driver,
|
|||||||
if (entry->d_name[0] == '.')
|
if (entry->d_name[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!hasSuffix(entry->d_name, ".xml"))
|
if (!virFileHasSuffix(entry->d_name, ".xml"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (qemudMakeConfigPath(configDir, entry->d_name, NULL, path, PATH_MAX) < 0) {
|
if (virFileBuildPath(configDir, entry->d_name, NULL, path, PATH_MAX) < 0) {
|
||||||
qemudLog(QEMUD_WARN, "Config filename '%s/%s' is too long",
|
qemudLog(QEMUD_WARN, "Config filename '%s/%s' is too long",
|
||||||
configDir, entry->d_name);
|
configDir, entry->d_name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemudMakeConfigPath(autostartDir, entry->d_name, NULL, autostartLink, PATH_MAX) < 0) {
|
if (virFileBuildPath(autostartDir, entry->d_name, NULL, autostartLink, PATH_MAX) < 0) {
|
||||||
qemudLog(QEMUD_WARN, "Autostart link path '%s/%s' is too long",
|
qemudLog(QEMUD_WARN, "Autostart link path '%s/%s' is too long",
|
||||||
autostartDir, entry->d_name);
|
autostartDir, entry->d_name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!qemudReadFile(path, xml, QEMUD_MAX_XML_LEN))
|
if (virFileReadAll(path, xml, QEMUD_MAX_XML_LEN) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (isGuest)
|
if (isGuest)
|
||||||
|
@ -362,7 +362,6 @@ int qemudDeleteConfig (virConnectPtr conn,
|
|||||||
struct qemud_driver *driver,
|
struct qemud_driver *driver,
|
||||||
const char *configFile,
|
const char *configFile,
|
||||||
const char *name);
|
const char *name);
|
||||||
int qemudEnsureDir (const char *path);
|
|
||||||
|
|
||||||
void qemudFreeVMDef (struct qemud_vm_def *vm);
|
void qemudFreeVMDef (struct qemud_vm_def *vm);
|
||||||
void qemudFreeVM (struct qemud_vm *vm);
|
void qemudFreeVM (struct qemud_vm *vm);
|
||||||
|
@ -632,7 +632,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
|
|||||||
strcat(logfile, vm->def->name);
|
strcat(logfile, vm->def->name);
|
||||||
strcat(logfile, ".log");
|
strcat(logfile, ".log");
|
||||||
|
|
||||||
if (qemudEnsureDir(driver->logDir) < 0) {
|
if (virFileMakePath(driver->logDir) < 0) {
|
||||||
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
"cannot create log directory %s: %s",
|
"cannot create log directory %s: %s",
|
||||||
driver->logDir, strerror(errno));
|
driver->logDir, strerror(errno));
|
||||||
@ -2458,7 +2458,7 @@ static int qemudDomainSetAutostart(virDomainPtr dom,
|
|||||||
if (autostart) {
|
if (autostart) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if ((err = qemudEnsureDir(driver->autostartDir))) {
|
if ((err = virFileMakePath(driver->autostartDir))) {
|
||||||
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
"cannot create autostart directory %s: %s",
|
"cannot create autostart directory %s: %s",
|
||||||
driver->autostartDir, strerror(err));
|
driver->autostartDir, strerror(err));
|
||||||
@ -2806,7 +2806,7 @@ static int qemudNetworkSetAutostart(virNetworkPtr net,
|
|||||||
if (autostart) {
|
if (autostart) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if ((err = qemudEnsureDir(driver->networkAutostartDir))) {
|
if ((err = virFileMakePath(driver->networkAutostartDir))) {
|
||||||
qemudReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR,
|
qemudReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR,
|
||||||
"cannot create autostart directory %s: %s",
|
"cannot create autostart directory %s: %s",
|
||||||
driver->networkAutostartDir, strerror(err));
|
driver->networkAutostartDir, strerror(err));
|
||||||
|
223
src/util.c
223
src/util.c
@ -30,6 +30,8 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <libvirt/virterror.h>
|
#include <libvirt/virterror.h>
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "buf.h"
|
#include "buf.h"
|
||||||
@ -37,6 +39,8 @@
|
|||||||
|
|
||||||
#define MAX_ERROR_LEN 1024
|
#define MAX_ERROR_LEN 1024
|
||||||
|
|
||||||
|
#define virLog(msg...) fprintf(stderr, msg)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ReportError(virConnectPtr conn,
|
ReportError(virConnectPtr conn,
|
||||||
virDomainPtr dom,
|
virDomainPtr dom,
|
||||||
@ -214,6 +218,7 @@ ssize_t safewrite(int fd, const void *buf, size_t count)
|
|||||||
size_t nwritten = 0;
|
size_t nwritten = 0;
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
int r = write(fd, buf, count);
|
int r = write(fd, buf, count);
|
||||||
|
|
||||||
if (r < 0 && errno == EINTR)
|
if (r < 0 && errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -226,3 +231,221 @@ ssize_t safewrite(int fd, const void *buf, size_t count)
|
|||||||
}
|
}
|
||||||
return nwritten;
|
return nwritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int virFileReadAll(const char *path,
|
||||||
|
char *buf,
|
||||||
|
unsigned int buflen)
|
||||||
|
{
|
||||||
|
FILE *fh;
|
||||||
|
struct stat st;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (!(fh = fopen(path, "r"))) {
|
||||||
|
virLog("Failed to open file '%s': %s",
|
||||||
|
path, strerror(errno));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fstat(fileno(fh), &st) < 0) {
|
||||||
|
virLog("Failed to stat file '%s': %s",
|
||||||
|
path, strerror(errno));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
virLog("Ignoring directory '%s'", path);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st.st_size >= (buflen-1)) {
|
||||||
|
virLog("File '%s' is too large", path);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = fread(buf, st.st_size, 1, fh)) != 1) {
|
||||||
|
virLog("Failed to read config file '%s': %s",
|
||||||
|
path, strerror(errno));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[st.st_size] = '\0';
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (fh)
|
||||||
|
fclose(fh);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int virFileMatchesNameSuffix(const char *file,
|
||||||
|
const char *name,
|
||||||
|
const char *suffix)
|
||||||
|
{
|
||||||
|
int filelen = strlen(file);
|
||||||
|
int namelen = strlen(name);
|
||||||
|
int suffixlen = strlen(suffix);
|
||||||
|
|
||||||
|
if (filelen == (namelen + suffixlen) &&
|
||||||
|
!strncmp(file, name, namelen) &&
|
||||||
|
!strncmp(file + namelen, suffix, suffixlen))
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int virFileHasSuffix(const char *str,
|
||||||
|
const char *suffix)
|
||||||
|
{
|
||||||
|
int len = strlen(str);
|
||||||
|
int suffixlen = strlen(suffix);
|
||||||
|
|
||||||
|
if (len < suffixlen)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return strcmp(str + len - suffixlen, suffix) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int virFileLinkPointsTo(const char *checkLink,
|
||||||
|
const char *checkDest)
|
||||||
|
{
|
||||||
|
char dest[PATH_MAX];
|
||||||
|
char real[PATH_MAX];
|
||||||
|
char checkReal[PATH_MAX];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
/* read the link destination */
|
||||||
|
if ((n = readlink(checkLink, dest, PATH_MAX)) < 0) {
|
||||||
|
switch (errno) {
|
||||||
|
case ENOENT:
|
||||||
|
case ENOTDIR:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case EINVAL:
|
||||||
|
virLog("File '%s' is not a symlink",
|
||||||
|
checkLink);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
virLog("Failed to read symlink '%s': %s",
|
||||||
|
checkLink, strerror(errno));
|
||||||
|
return 0;
|
||||||
|
} else if (n >= PATH_MAX) {
|
||||||
|
virLog("Symlink '%s' contents too long to fit in buffer",
|
||||||
|
checkLink);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest[n] = '\0';
|
||||||
|
|
||||||
|
/* make absolute */
|
||||||
|
if (dest[0] != '/') {
|
||||||
|
char dir[PATH_MAX];
|
||||||
|
char tmp[PATH_MAX];
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
strncpy(dir, checkLink, PATH_MAX);
|
||||||
|
dir[PATH_MAX-1] = '\0';
|
||||||
|
|
||||||
|
if (!(p = strrchr(dir, '/'))) {
|
||||||
|
virLog("Symlink path '%s' is not absolute", checkLink);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p == dir) /* handle unlikely root dir case */
|
||||||
|
p++;
|
||||||
|
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
if (virFileBuildPath(dir, dest, NULL, tmp, PATH_MAX) < 0) {
|
||||||
|
virLog("Path '%s/%s' is too long", dir, dest);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(dest, tmp, PATH_MAX);
|
||||||
|
dest[PATH_MAX-1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* canonicalize both paths */
|
||||||
|
if (!realpath(dest, real)) {
|
||||||
|
virLog("Failed to expand path '%s' :%s", dest, strerror(errno));
|
||||||
|
strncpy(real, dest, PATH_MAX);
|
||||||
|
real[PATH_MAX-1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!realpath(checkDest, checkReal)) {
|
||||||
|
virLog("Failed to expand path '%s' :%s", checkDest, strerror(errno));
|
||||||
|
strncpy(checkReal, checkDest, PATH_MAX);
|
||||||
|
checkReal[PATH_MAX-1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compare */
|
||||||
|
if (strcmp(checkReal, real) != 0) {
|
||||||
|
virLog("Link '%s' does not point to '%s', ignoring",
|
||||||
|
checkLink, checkReal);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int virFileMakePath(const char *path)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
char parent[PATH_MAX];
|
||||||
|
char *p;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (stat(path, &st) >= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
strncpy(parent, path, PATH_MAX);
|
||||||
|
parent[PATH_MAX - 1] = '\0';
|
||||||
|
|
||||||
|
if (!(p = strrchr(parent, '/')))
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (p == parent)
|
||||||
|
return EPERM;
|
||||||
|
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
if ((err = virFileMakePath(parent)))
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (mkdir(path, 0777) < 0 && errno != EEXIST)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build up a fully qualfiied path for a config file to be
|
||||||
|
* associated with a persistent guest or network */
|
||||||
|
int virFileBuildPath(const char *dir,
|
||||||
|
const char *name,
|
||||||
|
const char *ext,
|
||||||
|
char *buf,
|
||||||
|
unsigned int buflen)
|
||||||
|
{
|
||||||
|
if ((strlen(dir) + 1 + strlen(name) + (ext ? strlen(ext) : 0) + 1) >= (buflen-1))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
strcpy(buf, dir);
|
||||||
|
strcat(buf, "/");
|
||||||
|
strcat(buf, name);
|
||||||
|
if (ext)
|
||||||
|
strcat(buf, ext);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* indent-tabs-mode: nil
|
||||||
|
* c-indent-level: 4
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* tab-width: 4
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
|
29
src/util.h
29
src/util.h
@ -21,8 +21,37 @@
|
|||||||
* File created Jul 18, 2007 - Shuveb Hussain <shuveb@binarykarma.com>
|
* File created Jul 18, 2007 - Shuveb Hussain <shuveb@binarykarma.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef __VIR_UTIL_H__
|
||||||
|
#define __VIR_UTIL_H__
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
int virExec(virConnectPtr conn, char **argv, int *retpid, int infd, int *outfd, int *errfd);
|
int virExec(virConnectPtr conn, char **argv, int *retpid, int infd, int *outfd, int *errfd);
|
||||||
int virExecNonBlock(virConnectPtr conn, char **argv, int *retpid, int infd, int *outfd, int *errfd);
|
int virExecNonBlock(virConnectPtr conn, char **argv, int *retpid, int infd, int *outfd, int *errfd);
|
||||||
|
|
||||||
int saferead(int fd, void *buf, size_t count);
|
int saferead(int fd, void *buf, size_t count);
|
||||||
ssize_t safewrite(int fd, const void *buf, size_t count);
|
ssize_t safewrite(int fd, const void *buf, size_t count);
|
||||||
|
|
||||||
|
int virFileReadAll(const char *path,
|
||||||
|
char *buf,
|
||||||
|
unsigned int buflen);
|
||||||
|
|
||||||
|
int virFileMatchesNameSuffix(const char *file,
|
||||||
|
const char *name,
|
||||||
|
const char *suffix);
|
||||||
|
|
||||||
|
int virFileHasSuffix(const char *str,
|
||||||
|
const char *suffix);
|
||||||
|
|
||||||
|
int virFileLinkPointsTo(const char *checkLink,
|
||||||
|
const char *checkDest);
|
||||||
|
int virFileMakePath(const char *path);
|
||||||
|
|
||||||
|
int virFileBuildPath(const char *dir,
|
||||||
|
const char *name,
|
||||||
|
const char *ext,
|
||||||
|
char *buf,
|
||||||
|
unsigned int buflen);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __VIR_UTIL_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user