From 4cd62fe30690932977c7a7937f0ee22a4699df54 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 3 Dec 2007 14:30:46 +0000 Subject: [PATCH] Move generic file & I/O routines out of QEMU driver into util.c --- ChangeLog | 10 ++ src/qemu_conf.c | 256 ++++------------------------------------------ src/qemu_conf.h | 1 - src/qemu_driver.c | 6 +- src/util.c | 223 ++++++++++++++++++++++++++++++++++++++++ src/util.h | 29 ++++++ 6 files changed, 285 insertions(+), 240 deletions(-) diff --git a/ChangeLog b/ChangeLog index ba1cc573d2..a94af0cf7f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +Mon Dec 3 9:10:10 EST 2007 Daniel P. Berrange + + * 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 * src/xen_unified.[ch] src/proxy_internal.c src/xen_internal.c diff --git a/src/qemu_conf.c b/src/qemu_conf.c index 12741b481f..2635b334d4 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -48,6 +48,7 @@ #include "uuid.h" #include "buf.h" #include "conf.h" +#include "util.h" #define qemudLog(level, msg...) fprintf(stderr, msg) @@ -227,55 +228,6 @@ void qemudFreeVM(struct qemud_vm *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, as supported by QEMU - taken from 'qemu -M ?' for each arch */ @@ -2075,22 +2027,22 @@ qemudSaveVMDef(virConnectPtr conn, if (vm->configFile[0] == '\0') { int err; - if ((err = qemudEnsureDir(driver->configDir))) { + if ((err = virFileMakePath(driver->configDir))) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot create config directory %s: %s", driver->configDir, strerror(err)); return -1; } - if (qemudMakeConfigPath(driver->configDir, def->name, ".xml", - vm->configFile, PATH_MAX) < 0) { + if (virFileBuildPath(driver->configDir, def->name, ".xml", + vm->configFile, PATH_MAX) < 0) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot construct config file path"); return -1; } - if (qemudMakeConfigPath(driver->autostartDir, def->name, ".xml", - vm->autostartLink, PATH_MAX) < 0) { + if (virFileBuildPath(driver->autostartDir, def->name, ".xml", + vm->autostartLink, PATH_MAX) < 0) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot construct autostart link path"); vm->configFile[0] = '\0'; @@ -2114,7 +2066,7 @@ static int qemudSaveNetworkConfig(virConnectPtr conn, return -1; } - if ((err = qemudEnsureDir(driver->networkConfigDir))) { + if ((err = virFileMakePath(driver->networkConfigDir))) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot create config directory %s: %s", driver->networkConfigDir, strerror(err)); @@ -2521,22 +2473,22 @@ qemudSaveNetworkDef(virConnectPtr conn, if (network->configFile[0] == '\0') { int err; - if ((err = qemudEnsureDir(driver->networkConfigDir))) { + if ((err = virFileMakePath(driver->networkConfigDir))) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot create config directory %s: %s", driver->networkConfigDir, strerror(err)); return -1; } - if (qemudMakeConfigPath(driver->networkConfigDir, def->name, ".xml", - network->configFile, PATH_MAX) < 0) { + if (virFileBuildPath(driver->networkConfigDir, def->name, ".xml", + network->configFile, PATH_MAX) < 0) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot construct config file path"); return -1; } - if (qemudMakeConfigPath(driver->networkAutostartDir, def->name, ".xml", - network->autostartLink, PATH_MAX) < 0) { + if (virFileBuildPath(driver->networkAutostartDir, def->name, ".xml", + network->autostartLink, PATH_MAX) < 0) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot construct autostart link path"); network->configFile[0] = '\0'; @@ -2547,174 +2499,6 @@ qemudSaveNetworkDef(virConnectPtr conn, 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 * qemudLoadConfig(struct qemud_driver *driver, @@ -2732,7 +2516,7 @@ qemudLoadConfig(struct qemud_driver *driver, 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'", path, def->name); qemudFreeVMDef(def); @@ -2751,7 +2535,7 @@ qemudLoadConfig(struct qemud_driver *driver, strncpy(vm->autostartLink, autostartLink, PATH_MAX); vm->autostartLink[PATH_MAX-1] = '\0'; - vm->autostart = checkLinkPointsTo(vm->autostartLink, vm->configFile); + vm->autostart = virFileLinkPointsTo(vm->autostartLink, vm->configFile); return vm; } @@ -2772,7 +2556,7 @@ qemudLoadNetworkConfig(struct qemud_driver *driver, 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'", path, def->name); qemudFreeNetworkDef(def); @@ -2791,7 +2575,7 @@ qemudLoadNetworkConfig(struct qemud_driver *driver, strncpy(network->autostartLink, autostartLink, PATH_MAX); network->autostartLink[PATH_MAX-1] = '\0'; - network->autostart = checkLinkPointsTo(network->autostartLink, network->configFile); + network->autostart = virFileLinkPointsTo(network->autostartLink, network->configFile); return network; } @@ -2820,22 +2604,22 @@ int qemudScanConfigDir(struct qemud_driver *driver, if (entry->d_name[0] == '.') continue; - if (!hasSuffix(entry->d_name, ".xml")) + if (!virFileHasSuffix(entry->d_name, ".xml")) 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", configDir, entry->d_name); 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", autostartDir, entry->d_name); continue; } - if (!qemudReadFile(path, xml, QEMUD_MAX_XML_LEN)) + if (virFileReadAll(path, xml, QEMUD_MAX_XML_LEN) < 0) continue; if (isGuest) diff --git a/src/qemu_conf.h b/src/qemu_conf.h index 7a2a27bf6f..69342cbfc9 100644 --- a/src/qemu_conf.h +++ b/src/qemu_conf.h @@ -362,7 +362,6 @@ int qemudDeleteConfig (virConnectPtr conn, struct qemud_driver *driver, const char *configFile, const char *name); -int qemudEnsureDir (const char *path); void qemudFreeVMDef (struct qemud_vm_def *vm); void qemudFreeVM (struct qemud_vm *vm); diff --git a/src/qemu_driver.c b/src/qemu_driver.c index a6982613ca..0be71a5631 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -632,7 +632,7 @@ static int qemudStartVMDaemon(virConnectPtr conn, strcat(logfile, vm->def->name); strcat(logfile, ".log"); - if (qemudEnsureDir(driver->logDir) < 0) { + if (virFileMakePath(driver->logDir) < 0) { qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "cannot create log directory %s: %s", driver->logDir, strerror(errno)); @@ -2458,7 +2458,7 @@ static int qemudDomainSetAutostart(virDomainPtr dom, if (autostart) { int err; - if ((err = qemudEnsureDir(driver->autostartDir))) { + if ((err = virFileMakePath(driver->autostartDir))) { qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, "cannot create autostart directory %s: %s", driver->autostartDir, strerror(err)); @@ -2806,7 +2806,7 @@ static int qemudNetworkSetAutostart(virNetworkPtr net, if (autostart) { int err; - if ((err = qemudEnsureDir(driver->networkAutostartDir))) { + if ((err = virFileMakePath(driver->networkAutostartDir))) { qemudReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR, "cannot create autostart directory %s: %s", driver->networkAutostartDir, strerror(err)); diff --git a/src/util.c b/src/util.c index c964a6355c..2c970160de 100644 --- a/src/util.c +++ b/src/util.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include "event.h" #include "buf.h" @@ -37,6 +39,8 @@ #define MAX_ERROR_LEN 1024 +#define virLog(msg...) fprintf(stderr, msg) + static void ReportError(virConnectPtr conn, virDomainPtr dom, @@ -214,6 +218,7 @@ ssize_t safewrite(int fd, const void *buf, size_t count) size_t nwritten = 0; while (count > 0) { int r = write(fd, buf, count); + if (r < 0 && errno == EINTR) continue; if (r < 0) @@ -226,3 +231,221 @@ ssize_t safewrite(int fd, const void *buf, size_t count) } 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: + */ diff --git a/src/util.h b/src/util.h index f69fac8601..a7c68d5b7a 100644 --- a/src/util.h +++ b/src/util.h @@ -21,8 +21,37 @@ * File created Jul 18, 2007 - Shuveb Hussain */ +#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 virExecNonBlock(virConnectPtr conn, char **argv, int *retpid, int infd, int *outfd, int *errfd); int saferead(int fd, 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__ */