Signed-off-by: Luyao Huang <lhuang@xxxxxxxxxx> --- configure.ac | 10 + po/POTFILES.in | 3 +- src/Makefile.am | 5 +- src/libvirt_private.syms | 16 ++ src/util/virshm.c | 623 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/virshm.h | 104 ++++++++ 6 files changed, 759 insertions(+), 2 deletions(-) create mode 100644 src/util/virshm.c create mode 100644 src/util/virshm.h diff --git a/configure.ac b/configure.ac index a7f38e8..940eb66 100644 --- a/configure.ac +++ b/configure.ac @@ -1176,6 +1176,16 @@ if test "$with_linux" = "yes"; then ]]) fi +dnl +dnl check for POSIX share memory functions +dnl +LIBRT_LIBS="" +AC_CHECK_LIB([rt],[shm_open],[LIBRT_LIBS="-lrt"]) +old_libs="$LIBS" +LIBS="$old_libs $LIBRT_LIBS" +AC_CHECK_FUNCS([shm_open]) +LIBS="$old_libs" +AC_SUBST([LIBRT_LIBS]) dnl Need to test if pkg-config exists PKG_PROG_PKG_CONFIG diff --git a/po/POTFILES.in b/po/POTFILES.in index a75f5ae..7687a82 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -215,8 +215,9 @@ src/util/virpolkit.c src/util/virportallocator.c src/util/virprocess.c src/util/virrandom.c -src/util/virsexpr.c src/util/virscsi.c +src/util/virsexpr.c +src/util/virshm.c src/util/virsocketaddr.c src/util/virstats.c src/util/virstorageencryption.c diff --git a/src/Makefile.am b/src/Makefile.am index 7338ab9..048a096 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -152,6 +152,7 @@ UTIL_SOURCES = \ util/virscsi.c util/virscsi.h \ util/virseclabel.c util/virseclabel.h \ util/virsexpr.c util/virsexpr.h \ + util/virshm.c util/virshm.h \ util/virsocketaddr.h util/virsocketaddr.c \ util/virstats.c util/virstats.h \ util/virstorageencryption.c util/virstorageencryption.h \ @@ -1048,7 +1049,7 @@ libvirt_util_la_LIBADD = $(CAPNG_LIBS) $(YAJL_LIBS) $(LIBNL_LIBS) \ $(THREAD_LIBS) $(AUDIT_LIBS) $(DEVMAPPER_LIBS) \ $(LIB_CLOCK_GETTIME) $(DBUS_LIBS) $(MSCOM_LIBS) $(LIBXML_LIBS) \ $(SECDRIVER_LIBS) $(NUMACTL_LIBS) $(SYSTEMD_DAEMON_LIBS) \ - $(POLKIT_LIBS) + $(POLKIT_LIBS) $(LIBRT_LIBS) noinst_LTLIBRARIES += libvirt_conf.la @@ -1284,6 +1285,7 @@ libvirt_driver_qemu_impl_la_LIBADD = $(CAPNG_LIBS) \ $(GNUTLS_LIBS) \ $(LIBNL_LIBS) \ $(LIBXML_LIBS) \ + $(LIBRT_LIBS) \ $(NULL) libvirt_driver_qemu_impl_la_SOURCES = $(QEMU_DRIVER_SOURCES) @@ -2264,6 +2266,7 @@ libvirt_setuid_rpc_client_la_LDFLAGS = \ $(AM_LDFLAGS) \ $(LIBXML_LIBS) \ $(SECDRIVER_LIBS) \ + $(LIBRT_LIBS) \ $(NULL) libvirt_setuid_rpc_client_la_CFLAGS = \ -DLIBVIRT_SETUID_RPC_CLIENT \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index af73177..977fd34 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2078,6 +2078,22 @@ sexpr_u64; string2sexpr; +# util/virshm.h +virShmBuildPath; +virShmCreate; +virShmObjectFree; +virShmObjectNew; +virShmObjectListAdd; +virShmObjectListDel; +virShmObjectFindByName; +virShmObjectListGetDefault; +virShmObjectRemoveStateFile; +virShmObjectSaveState; +virShmOpen; +virShmRemoveUsedDomain; +virShmSetUsedDomain; +virShmUnlink; + # util/virsocketaddr.h virSocketAddrBroadcast; virSocketAddrBroadcastByPrefix; diff --git a/src/util/virshm.c b/src/util/virshm.c new file mode 100644 index 0000000..7ab39be --- /dev/null +++ b/src/util/virshm.c @@ -0,0 +1,623 @@ +/* + * virshm.c: helper API for POSIX share memory + * + * Copyright (C) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <config.h> + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> + +#ifdef HAVE_SHM_OPEN +# include <sys/mman.h> +#endif + +#include "virshm.h" +#include "virxml.h" +#include "virbuffer.h" +#include "virerror.h" +#include "virstring.h" +#include "virlog.h" +#include "virutil.h" +#include "viralloc.h" +#include "virfile.h" +#include "configmake.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("util.shm"); + +#define SHMEM_STATE_DIR LOCALSTATEDIR "/run/libvirt/shmem" + +VIR_ENUM_IMPL(virShmObject, VIR_SHM_TYPE_LAST, + "shm", + "server"); + +static virClassPtr virShmObjectListClass; + +static virShmObjectListPtr mainlist; /* global shm object list */ + +static void virShmObjectListDispose(void *obj); + +static int +virShmObjectListLoadState(virShmObjectPtr *shmobj, + const char *stateDir, + const char *name) +{ + char *stateFile = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlDocPtr xml = NULL; + virShmObjectPtr tmpshm; + xmlNodePtr *usagenode = NULL; + xmlNodePtr save = NULL; + int ret = -1; + char *drivername = NULL; + char *shmtype = NULL; + int nusages; + + if (VIR_ALLOC(tmpshm) < 0) + return -1; + + if (!(stateFile = virFileBuildPath(stateDir, name, ".xml"))) + goto error; + + if (!(xml = virXMLParseFileCtxt(stateFile, &ctxt))) + goto error; + + tmpshm->name = virXPathString("string(./name)", ctxt); + if (!tmpshm->name) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("shmem missing name attribute")); + goto error; + } + + shmtype = virXPathString("string(./type)", ctxt); + if (!shmtype) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("shmem missing type attribute")); + goto error; + } + if ((tmpshm->type = virShmObjectTypeFromString(shmtype)) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("invalid shmem object type %s"), shmtype); + goto error; + } + + if (virXPathULongLong("string(./size)", ctxt, &tmpshm->size) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("shmem missing or have invalid size attribute")); + goto error; + } + + tmpshm->path = virXPathString("string(./path)", ctxt); + if (virXPathBoolean("boolean(./othercreate)", ctxt)) + tmpshm->othercreate = true; + + if (!(drivername = virXPathString("string(./@driver)", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("shmem usage element missing driver attribute")); + goto error; + } + nusages = virXPathNodeSet("./domain", ctxt, &usagenode); + if (nusages < 0) + goto error; + + if (nusages > 0) { + size_t i; + + for (i = 0; i < nusages; i++) { + char *domainname; + + save = ctxt->node; + ctxt->node = usagenode[i]; + + if (!(domainname = virXPathString("string(./@name)", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("shmem domain element missing name attribute")); + goto error; + } + + if (virShmSetUsedDomain(tmpshm, drivername, domainname) < 0) { + VIR_FREE(domainname); + goto error; + } + VIR_FREE(domainname); + ctxt->node = save; + } + } + *shmobj = tmpshm; + ret = 0; + cleanup: + VIR_FREE(stateFile); + VIR_FREE(drivername); + VIR_FREE(shmtype); + xmlFreeDoc(xml); + xmlXPathFreeContext(ctxt); + return ret; + + error: + virShmObjectFree(tmpshm); + goto cleanup; +} + +static int +virShmObjectListLoadAllState(virShmObjectListPtr list) +{ + DIR *dir; + struct dirent *entry; + + if (!(dir = opendir(list->stateDir))) { + if (errno == ENOENT) + return 0; + virReportSystemError(errno, _("Failed to open dir '%s'"), list->stateDir); + return -1; + } + + while (virDirRead(dir, &entry, list->stateDir) > 0) { + virShmObjectPtr shmobj; + + if (entry->d_name[0] == '.' || + !virFileStripSuffix(entry->d_name, ".xml")) + continue; + if (virShmObjectListLoadState(&shmobj, list->stateDir, entry->d_name) < 0) + continue; + if (virShmObjectListAdd(list, shmobj) < 0) + continue; + } + closedir(dir); + return 0; +} + +static virShmObjectListPtr +virShmObjectListNew(void) +{ + virShmObjectListPtr list; + bool privileged = geteuid() == 0; + + if (!(list = virObjectLockableNew(virShmObjectListClass))) + return NULL; + + virObjectLock(list); + if (privileged) { + if (VIR_STRDUP(list->stateDir, SHMEM_STATE_DIR) < 0) + goto error; + } else { + char *rundir = NULL; + + if (!(rundir = virGetUserRuntimeDirectory())) + goto error; + + if (virAsprintf(&list->stateDir, "%s/shmem", rundir) < 0) { + VIR_FREE(rundir); + goto error; + } + VIR_FREE(rundir); + } + if (virFileMakePath(list->stateDir) < 0) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Failed to create state dir '%s'"), + list->stateDir); + goto error; + } + if (virShmObjectListLoadAllState(list) < 0) + goto error; + + virObjectUnlock(list); + return list; + + error: + virObjectUnlock(list); + virObjectUnref(list); + return NULL; +} + +static int +virShmOnceInit(void) +{ + if (!(virShmObjectListClass = virClassNew(virClassForObjectLockable(), + "virShmObjectList", + sizeof(virShmObjectList), + virShmObjectListDispose))) + return -1; + + if (!(mainlist = virShmObjectListNew())) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virShm) + +virShmObjectListPtr +virShmObjectListGetDefault(void) +{ + if (virShmInitialize() < 0) + return NULL; + + return virObjectRef(mainlist); +} + +int +virShmSetUsedDomain(virShmObjectPtr shmobj, + const char *drvname, + const char *domname) +{ + char *tmpdomain = NULL; + + if (shmobj->drvname) { + if (STRNEQ(drvname, shmobj->drvname)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot use one shmem for different driver")); + goto error; + } + } else { + if (VIR_STRDUP(shmobj->drvname, drvname) < 0) + goto error; + } + + if (VIR_STRDUP(tmpdomain, domname) < 0) + goto error; + + if (VIR_APPEND_ELEMENT(shmobj->domains, shmobj->ndomains, tmpdomain) < 0) + goto error; + + return 0; + + error: + VIR_FREE(tmpdomain); + return -1; +} + +void +virShmObjectFree(virShmObjectPtr shmobj) +{ + size_t i; + + if (!shmobj) + return; + + VIR_FREE(shmobj->name); + VIR_FREE(shmobj->path); + VIR_FREE(shmobj->drvname); + for (i = 0; i < shmobj->ndomains; i++) + VIR_FREE(shmobj->domains[i]); + VIR_FREE(shmobj->domains); + VIR_FREE(shmobj); +} + +virShmObjectPtr +virShmObjectNew(const char *name, + unsigned long long size, + const char *path, + int type, + bool othercreate, + const char *drvname, + const char *domname) +{ + virShmObjectPtr shmobj; + + if (VIR_ALLOC(shmobj) < 0) + return NULL; + + shmobj->size = size; + shmobj->type = type; + + if (VIR_STRDUP(shmobj->name, name) < 0) + goto error; + + if (path) { + if (VIR_STRDUP(shmobj->path, path) < 0) + goto error; + } else { + VIR_FREE(shmobj->path); + } + shmobj->othercreate = othercreate; + + if (virShmSetUsedDomain(shmobj, drvname, domname) < 0) + goto error; + + return shmobj; + + error: + virShmObjectFree(shmobj); + return NULL; +} + +static void +virShmObjectListDispose(void *obj) +{ + virShmObjectListPtr list = obj; + size_t i; + + for (i = 0; i < list->nshmobjs; i++) + virShmObjectFree(list->shmobjs[i]); + + VIR_FREE(list->shmobjs); +} + +int +virShmObjectSaveState(virShmObjectPtr shmobj, + const char *stateDir) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + int ret = -1; + size_t i; + char *xml = NULL; + char *stateFile = NULL; + + virBufferAddLit(&buf, "<shmem>\n"); + virBufferAdjustIndent(&buf, 2); + + virBufferAsprintf(&buf, "<name>%s</name>\n", shmobj->name); + + virBufferAsprintf(&buf, "<type>%s</type>\n", virShmObjectTypeToString(shmobj->type)); + + virBufferAsprintf(&buf, "<size>%llu</size>\n", shmobj->size); + if (shmobj->path) + virBufferAsprintf(&buf, "<path>%s</path>\n", shmobj->path); + if (shmobj->othercreate) + virBufferAddLit(&buf, "<othercreate/>\n"); + virBufferAsprintf(&buf, "<driver>%s</driver>\n", shmobj->drvname); + for (i = 0; i < shmobj->ndomains; i++) + virBufferAsprintf(&buf, "<domain name='%s'/>\n", shmobj->domains[i]); + + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "</shmem>\n"); + + if (virBufferCheckError(&buf) < 0) + goto cleanup; + + if (!(xml = virBufferContentAndReset(&buf))) + goto cleanup; + + if (!(stateFile = virFileBuildPath(stateDir, shmobj->name, ".xml"))) + goto cleanup; + + if (virXMLSaveFile(stateFile, NULL, NULL, xml) < 0) + goto cleanup; + + ret = 0; + + cleanup: + VIR_FREE(stateFile); + VIR_FREE(xml); + return ret; +} + +int +virShmRemoveUsedDomain(virShmObjectPtr shmobj, + const char *drvname, + const char *domname) +{ + size_t i; + + if (shmobj->drvname) { + if (STRNEQ(drvname, shmobj->drvname)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot use one shmem for different driver")); + return -1; + } + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot get shmem object driver name")); + return -1; + } + + for (i = 0; i < shmobj->ndomains; i++) { + if (STREQ(shmobj->domains[i], domname)) { + VIR_FREE(shmobj->domains[i]); + VIR_DELETE_ELEMENT(shmobj->domains, i, shmobj->ndomains); + return 0; + } + } + + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot find domname in shmem object domain list")); + return -1; +} + +int +virShmObjectRemoveStateFile(virShmObjectListPtr list, + const char *name) +{ + char *stateFile = NULL; + + if (!(stateFile = virFileBuildPath(list->stateDir, name, ".xml"))) + return -1; + unlink(stateFile); + VIR_FREE(stateFile); + return 0; +} + +int +virShmObjectListDel(virShmObjectListPtr list, + virShmObjectPtr shmobj) +{ + size_t i; + + for (i = 0; i < list->nshmobjs; i++) { + virShmObjectPtr tmp = list->shmobjs[i]; + + if (STREQ(tmp->name, shmobj->name)) { + VIR_DELETE_ELEMENT(list->shmobjs, i, list->nshmobjs); + return 0; + } + } + return -1; +} + +virShmObjectPtr +virShmObjectFindByName(virShmObjectListPtr list, + const char *name) +{ + size_t i; + + for (i = 0; i < list->nshmobjs; i++) { + if (STREQ_NULLABLE(list->shmobjs[i]->name, name)) + return list->shmobjs[i]; + } + + return NULL; +} + +int +virShmObjectListAdd(virShmObjectListPtr list, + virShmObjectPtr shmobj) +{ + if (virShmObjectFindByName(list, shmobj->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("A share memory object named '%s' already exists"), + shmobj->name); + return -1; + } + + return VIR_APPEND_ELEMENT(list->shmobjs, list->nshmobjs, shmobj); +} + +#ifdef HAVE_SHM_OPEN +int +virShmOpen(const char *name, + unsigned long long size, + mode_t mode) +{ + int fd = -1; + struct stat sb; + + if ((fd = shm_open(name, O_RDWR, mode)) < 0) { + virReportSystemError(errno, + _("Unable to open shared memory" + " objects '%s'"), + name); + return -1; + } + + if (fstat(fd, &sb) < 0) { + virReportSystemError(errno, + _("cannot stat file '%s'"), name); + goto error; + } + + if (sb.st_size < size) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("already exist shared memory object" + " size %ju is smaller than required size %llu"), + (uintmax_t)sb.st_size, size); + goto error; + } + + return fd; + + error: + VIR_FORCE_CLOSE(fd); + return -1; +} + +int +virShmCreate(const char *name, + unsigned long long size, + bool outerr, + bool *othercreate, + mode_t mode) +{ + int fd = -1; + + fd = shm_open(name, O_RDWR|O_CREAT|O_EXCL, mode); + + if (fd > 0) { + if (ftruncate(fd, size) != 0) { + virReportSystemError(errno, + _("Unable to truncate" + " file descriptor to %llu"), + size); + ignore_value(shm_unlink(name)); + VIR_FORCE_CLOSE(fd); + return -1; + } + } else if (errno == EEXIST) { + if (outerr) { + virReportSystemError(errno, + _("shared memory objects" + " '%s' is already exist"), + name); + return -1; + } + + VIR_WARN("shared memory objects '%s' is already exist", name); + *othercreate = true; + + return virShmOpen(name, size, mode); + } else { + virReportSystemError(errno, + _("Unable to create shared memory" + " objects '%s'"), + name); + return -1; + } + + return fd; +} + +int +virShmUnlink(const char *name) +{ + int ret; + + if ((ret = shm_unlink(name)) < 0) { + virReportSystemError(errno, + _("Unable to delete shared memory" + " objects '%s'"), + name); + } + return ret; +} + +# if defined(__linux__) +# define SHM_DEFAULT_PATH "/dev/shm" + +int +virShmBuildPath(const char *name, char **path) +{ + + if (virAsprintf(path, "%s/%s", SHM_DEFAULT_PATH, name) < 0) + return -1; + + if (!virFileExists(*path)) { + virReportSystemError(errno, + _("could not access %s"), + *path); + VIR_FREE(*path); + return -1; + } + return 0; +} + +# else + +int +virShmBuildPath(const char *name ATTRIBUTE_UNUSED, + char **path ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Cannot get share memory object path on this platform")); + return -2; +} + +# endif +#endif /* HAVE_SHM_OPEN */ diff --git a/src/util/virshm.h b/src/util/virshm.h new file mode 100644 index 0000000..945a541 --- /dev/null +++ b/src/util/virshm.h @@ -0,0 +1,104 @@ +/* + * virshm.h: helper API for POSIX share memory + * + * Copyright (C) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#ifndef __VIR_SHM_H__ +# define __VIR_SHM_H__ + +# include "internal.h" +# include "virutil.h" +# include "virobject.h" + +typedef enum { + VIR_SHM_TYPE_SHM = 0, + VIR_SHM_TYPE_SERVER, + + VIR_SHM_TYPE_LAST +} virShmObjectType; + +typedef struct _virShmObject virShmObject; +typedef virShmObject *virShmObjectPtr; +struct _virShmObject { + char *name; /* shmem object name */ + int type; /* shmem object type */ + unsigned long long size; /* size of shmem object */ + char *path; /* shmem path */ + bool othercreate; /* a bool parameter record if the shm is created by libvirt */ + + char *drvname; /* which driver */ + char **domains; /* domain(s) using this shm */ + size_t ndomains; /* number of useds */ +}; + +VIR_ENUM_DECL(virShmObject); + +typedef struct _virShmObjectList virShmObjectList; +typedef virShmObjectList *virShmObjectListPtr; +struct _virShmObjectList { + virObjectLockable parent; + char *stateDir; + size_t nshmobjs; + virShmObjectPtr *shmobjs; +}; + +virShmObjectListPtr virShmObjectListGetDefault(void); + +int virShmSetUsedDomain(virShmObjectPtr shmobj, const char *drvname, const char *domname) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); +int virShmRemoveUsedDomain(virShmObjectPtr shmobj, const char *drvname, const char *domname) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); +void virShmObjectFree(virShmObjectPtr shmobj); +virShmObjectPtr virShmObjectNew(const char *name, unsigned long long size, + const char *path, int type, bool othercreate, + const char *drvname, const char *domname) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(6) + ATTRIBUTE_NONNULL(7); +int virShmObjectSaveState(virShmObjectPtr shmobj, const char *stateDir) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int virShmObjectRemoveStateFile(virShmObjectListPtr list, const char *name) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int virShmObjectListAdd(virShmObjectListPtr list, virShmObjectPtr shmobj) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int virShmObjectListDel(virShmObjectListPtr list, virShmObjectPtr shmobj) + ATTRIBUTE_NONNULL(1); +virShmObjectPtr virShmObjectFindByName(virShmObjectListPtr list, + const char *name) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +# ifdef HAVE_SHM_OPEN +int virShmCreate(const char *name, unsigned long long size, + bool outerr, bool *othercreate, mode_t mode) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4); +int virShmOpen(const char *name, + unsigned long long size, + mode_t mode) + ATTRIBUTE_NONNULL(1); +int virShmUnlink(const char *name) + ATTRIBUTE_NONNULL(1); +int virShmBuildPath(const char *name, char **path) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +# else /* HAVE_SHM_OPEN */ +# define virShmCreate(name, size, outerr, othercreate, mode) -2 +# define virShmOpen(name, size, mode) -2 +# define virShmUnlink(name) -2 +# define virShmBuildPath(name, path) -2 + +# endif /* HAVE_SHM_OPEN */ +#endif /* __VIR_SHM_H__ */ -- 1.8.3.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list