On Tue, Feb 12, 2008 at 04:36:04AM +0000, Daniel P. Berrange wrote: > This patch provides the general purpose code for the storage driver. > The storage_driver.{c,h} file implements the libvirt internal storage > driver API. The storage_conf.{c,h} file takes care of parsing and > formatting the XML for pools and volumes. This should be reusable by > the test driver's impl of the storage APIs in the future. The final > storage_backend.{c,h} file provides a 2nd level internal driver API. > This allows the main storage driver to call into storage pool specific > impls for iSCSI, disk, filesystem, LVM and more. The storage_backend.h > definitions allow the specific drivers to declare particular parts of > the generic pool XML which are mandatory. For example, a disk pool > always requires a source device element. > > This patch adds AC_SYS_LARGEFILE to turn on large file support inside > libvirt globally, allowing us to manage files > 2GB. Makefile.maint | 2 b/src/storage_backend.c | 88 ++ b/src/storage_backend.h | 121 +++ b/src/storage_conf.c | 1251 +++++++++++++++++++++++++++++++++++++ b/src/storage_conf.h | 314 +++++++++ b/src/storage_driver.c | 1261 ++++++++++++++++++++++++++++++++++++++ b/src/storage_driver.h | 45 + configure.in | 2 docs/devhelp/libvirt-libvirt.html | 39 - include/libvirt/virterror.h | 2 po/POTFILES.in | 3 src/Makefile.am | 3 src/libvirt.c | 2 src/virterror.c | 12 14 files changed, 3122 insertions(+), 23 deletions(-) diff -r d043e3715bce Makefile.maint --- a/Makefile.maint Tue Feb 19 16:26:35 2008 -0500 +++ b/Makefile.maint Tue Feb 19 16:59:10 2008 -0500 @@ -289,7 +289,7 @@ sc_two_space_separator_in_usage: 1>&2; exit 1; } || : err_func_re = \ -(DISABLE_fprintf|qemudLog|(xmlRpc|vir(Xend|XML|Hash|Conf|Test|LibConn))Error) +(DISABLE_fprintf|qemudLog|(xmlRpc|vir(Xend|XML|Hash|Conf|Test|LibConn|StorageReport))Error) # Look for diagnostics that aren't marked for translation. # This won't find any for which error's format string is on a separate line. diff -r d043e3715bce configure.in --- a/configure.in Tue Feb 19 16:26:35 2008 -0500 +++ b/configure.in Tue Feb 19 16:59:10 2008 -0500 @@ -689,6 +689,8 @@ AC_SUBST(CYGWIN_EXTRA_PYTHON_LIBADD) AC_SUBST(CYGWIN_EXTRA_PYTHON_LIBADD) AC_SUBST(MINGW_EXTRA_LDFLAGS) +AC_SYS_LARGEFILE + # very annoying rm -f COPYING cp COPYING.LIB COPYING diff -r d043e3715bce docs/devhelp/libvirt-libvirt.html --- a/docs/devhelp/libvirt-libvirt.html Tue Feb 19 16:26:35 2008 -0500 +++ b/docs/devhelp/libvirt-libvirt.html Tue Feb 19 16:59:10 2008 -0500 @@ -112,7 +112,7 @@ int <a href="#virDomainFree">virDomainFr int <a href="#virDomainFree">virDomainFree</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain); const char * <a href="#virStoragePoolGetName">virStoragePoolGetName</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool); int <a href="#virDomainSetAutostart">virDomainSetAutostart</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain, <br/> int autostart); -<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> <a href="#virStoragePoolDefineXML">virStoragePoolDefineXML</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * xml); +<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> <a href="#virStoragePoolDefineXML">virStoragePoolDefineXML</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * xml, <br/> unsigned int flags); <a href="libvirt-libvirt.html#virStorageVolPtr">virStorageVolPtr</a> <a href="#virStorageVolLookupByPath">virStorageVolLookupByPath</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * path); <a href="libvirt-libvirt.html#virStorageVolPtr">virStorageVolPtr</a> <a href="#virStorageVolLookupByName">virStorageVolLookupByName</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> const char * name); <a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> <a href="#virDomainCreateLinux">virDomainCreateLinux</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * xmlDesc, <br/> unsigned int flags); @@ -126,7 +126,6 @@ int <a href="#virConnectNumOfNetworks">v <a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> <a href="#virStoragePoolLookupByUUIDString">virStoragePoolLookupByUUIDString</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * uuidstr); char * <a href="#virDomainGetXMLDesc">virDomainGetXMLDesc</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain, <br/> int flags); int <a href="#virStoragePoolGetUUID">virStoragePoolGetUUID</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> unsigned char * uuid); -int <a href="#virConnectDiscoverStoragePools">virConnectDiscoverStoragePools</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * hostname, <br/> const char * type, <br/> unsigned int flags, <br/> char ** * xmlDesc); int <a href="#virStorageVolGetInfo">virStorageVolGetInfo</a> (<a href="libvirt-libvirt.html#virStorageVolPtr">virStorageVolPtr</a> vol, <br/> <a href="libvirt-libvirt.html#virStorageVolInfoPtr">virStorageVolInfoPtr</a> info); const char * <a href="#virNetworkGetName">virNetworkGetName</a> (<a href="libvirt-libvirt.html#virNetworkPtr">virNetworkPtr</a> network); int <a href="#virNetworkDestroy">virNetworkDestroy</a> (<a href="libvirt-libvirt.html#virNetworkPtr">virNetworkPtr</a> network); @@ -173,7 +172,7 @@ int <a href="#virDomainGetUUID">virDomai int <a href="#virDomainGetUUID">virDomainGetUUID</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain, <br/> unsigned char * uuid); <a href="libvirt-libvirt.html#virNetworkPtr">virNetworkPtr</a> <a href="#virNetworkCreateXML">virNetworkCreateXML</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * xmlDesc); int <a href="#virDomainGetVcpus">virDomainGetVcpus</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain, <br/> <a href="libvirt-libvirt.html#virVcpuInfoPtr">virVcpuInfoPtr</a> info, <br/> int maxinfo, <br/> unsigned char * cpumaps, <br/> int maplen); -<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> <a href="#virStoragePoolCreateXML">virStoragePoolCreateXML</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * xmlDesc); +<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> <a href="#virStoragePoolCreateXML">virStoragePoolCreateXML</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * xmlDesc, <br/> unsigned int flags); int <a href="#virStoragePoolGetInfo">virStoragePoolGetInfo</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> <a href="libvirt-libvirt.html#virStoragePoolInfoPtr">virStoragePoolInfoPtr</a> info); int <a href="#virStoragePoolRefresh">virStoragePoolRefresh</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> unsigned int flags); int <a href="#virConnectNumOfDefinedDomains">virConnectNumOfDefinedDomains</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); @@ -210,7 +209,7 @@ int <a href="#virDomainGetUUIDString">vi <a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> <a href="#virDomainGetConnect">virDomainGetConnect</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> dom); int <a href="#virConnectNumOfDefinedStoragePools">virConnectNumOfDefinedStoragePools</a> (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn); <a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> <a href="#virConnectOpen">virConnectOpen</a> (const char * name); -int <a href="#virStoragePoolCreate">virStoragePoolCreate</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool); +int <a href="#virStoragePoolCreate">virStoragePoolCreate</a> (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> unsigned int flags); int <a href="#virDomainSetVcpus">virDomainSetVcpus</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain, <br/> unsigned int nvcpus); unsigned int <a href="#virDomainGetID">virDomainGetID</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> domain); int <a href="#virDomainInterfaceStats">virDomainInterfaceStats</a> (<a href="libvirt-libvirt.html#virDomainPtr">virDomainPtr</a> dom, <br/> const char * path, <br/> <a href="libvirt-libvirt.html#virDomainInterfaceStatsPtr">virDomainInterfaceStatsPtr</a> stats, <br/> size_t size); @@ -469,14 +468,14 @@ The content of this structure is not mad <div class="refsect2" lang="en"><h3><a name="virStoragePoolBuildFlags">Enum </a>virStoragePoolBuildFlags</h3><pre class="programlisting">enum <a href="#virStoragePoolBuildFlags">virStoragePoolBuildFlags</a> { <a name="VIR_STORAGE_POOL_BUILD_NEW">VIR_STORAGE_POOL_BUILD_NEW</a> = 0 /* Regular build from scratch */ <a name="VIR_STORAGE_POOL_BUILD_REPAIR">VIR_STORAGE_POOL_BUILD_REPAIR</a> = 1 /* Repair / reinitialize */ - <a name="VIR_STORAGE_POOL_BUILD_EXTEND">VIR_STORAGE_POOL_BUILD_EXTEND</a> = 2 /* Extend existing pool */ + <a name="VIR_STORAGE_POOL_BUILD_RESIZE">VIR_STORAGE_POOL_BUILD_RESIZE</a> = 2 /* Extend existing pool */ }; </pre><p/> </div> <hr/> <div class="refsect2" lang="en"><h3><a name="virStoragePoolDeleteFlags">Enum </a>virStoragePoolDeleteFlags</h3><pre class="programlisting">enum <a href="#virStoragePoolDeleteFlags">virStoragePoolDeleteFlags</a> { <a name="VIR_STORAGE_POOL_DELETE_NORMAL">VIR_STORAGE_POOL_DELETE_NORMAL</a> = 0 /* Delete metadata only (fast) */ - <a name="VIR_STORAGE_POOL_DELETE_CLEAR">VIR_STORAGE_POOL_DELETE_CLEAR</a> = 1 /* Clear all data to zeros (slow) */ + <a name="VIR_STORAGE_POOL_DELETE_ZEROED">VIR_STORAGE_POOL_DELETE_ZEROED</a> = 1 /* Clear all data to zeros (slow) */ }; </pre><p/> </div> @@ -515,7 +514,7 @@ The content of this structure is not mad <hr/> <div class="refsect2" lang="en"><h3><a name="virStorageVolDeleteFlags">Enum </a>virStorageVolDeleteFlags</h3><pre class="programlisting">enum <a href="#virStorageVolDeleteFlags">virStorageVolDeleteFlags</a> { <a name="VIR_STORAGE_VOL_DELETE_NORMAL">VIR_STORAGE_VOL_DELETE_NORMAL</a> = 0 /* Delete metadata only (fast) */ - <a name="VIR_STORAGE_VOL_DELETE_CLEAR">VIR_STORAGE_VOL_DELETE_CLEAR</a> = 1 /* Clear all data to zeros (slow) */ + <a name="VIR_STORAGE_VOL_DELETE_ZEROED">VIR_STORAGE_VOL_DELETE_ZEROED</a> = 1 /* Clear all data to zeros (slow) */ }; </pre><p/> </div> @@ -576,10 +575,6 @@ The content of this structure is not mad </pre><p>This function closes the connection to the Hypervisor. This should not be called if further interaction with the Hypervisor are needed especially if there is running domain which need further monitoring by the application.</p> <div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 in case of success or -1 in case of error.</td></tr></tbody></table></div></div> <hr/> - <div class="refsect2" lang="en"><h3><a name="virConnectDiscoverStoragePools"/>virConnectDiscoverStoragePools ()</h3><pre class="programlisting">int virConnectDiscoverStoragePools (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * hostname, <br/> const char * type, <br/> unsigned int flags, <br/> char ** * xmlDesc)<br/> -</pre><p>Talks to a host and attempt to auto-discover a set of exported storage pools available. eg For iSCSI this would be a set of iSCSI targets. For NFS this would be a list of exported paths. Each discovered pool is returned as an XML document suitable for feeding into <a href="libvirt-libvirt.html#virStoragePoolCreateXML">virStoragePoolCreateXML</a></p> -<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to hypervisor connection</td></tr><tr><td><span class="term"><i><tt>hostname</tt></i>:</span></td><td>host to discover pools on</td></tr><tr><td><span class="term"><i><tt>type</tt></i>:</span></td><td>type of storge pool to discover</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td>flags for discovery (unused, pass 0)</td></tr><tr><td><span class="term"><i><tt>xmlDesc</tt></i>:</span></td><td>return array of of XML documents, one per pool</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>number of discovered pools, or -1 on error</td></tr></tbody></table></div></div> - <hr/> <div class="refsect2" lang="en"><h3><a name="virConnectGetCapabilities"/>virConnectGetCapabilities ()</h3><pre class="programlisting">char * virConnectGetCapabilities (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn)<br/> </pre><p>Provides capabilities of the hypervisor / driver.</p> <div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to the hypervisor connection</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>NULL in case of error, or an XML string defining the capabilities. The client must free the returned string after use.</td></tr></tbody></table></div></div> @@ -924,28 +919,28 @@ The content of this structure is not mad </pre><p>Build the underlying storage pool</p> <div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>pool</tt></i>:</span></td><td>pointer to storage pool</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td/></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, or -1 upon failure</td></tr></tbody></table></div></div> <hr/> - <div class="refsect2" lang="en"><h3><a name="virStoragePoolCreate"/>virStoragePoolCreate ()</h3><pre class="programlisting">int virStoragePoolCreate (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool)<br/> + <div class="refsect2" lang="en"><h3><a name="virStoragePoolCreate"/>virStoragePoolCreate ()</h3><pre class="programlisting">int virStoragePoolCreate (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> unsigned int flags)<br/> </pre><p>Starts an inactive storage pool</p> -<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>pool</tt></i>:</span></td><td>pointer to storage pool</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, or -1 if it could not be started</td></tr></tbody></table></div></div> - <hr/> - <div class="refsect2" lang="en"><h3><a name="virStoragePoolCreateXML"/>virStoragePoolCreateXML ()</h3><pre class="programlisting"><a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> virStoragePoolCreateXML (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * xmlDesc)<br/> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>pool</tt></i>:</span></td><td>pointer to storage pool</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td/></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, or -1 if it could not be started</td></tr></tbody></table></div></div> + <hr/> + <div class="refsect2" lang="en"><h3><a name="virStoragePoolCreateXML"/>virStoragePoolCreateXML ()</h3><pre class="programlisting"><a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> virStoragePoolCreateXML (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * xmlDesc, <br/> unsigned int flags)<br/> </pre><p>Create a new storage based on its XML description. The pool is not persitent, so its definition will disappear when it is destroyed, or if the host is restarted</p> -<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to hypervisor connection</td></tr><tr><td><span class="term"><i><tt>xmlDesc</tt></i>:</span></td><td>XML description for new pool</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>a <a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> object, or NULL if creation failed</td></tr></tbody></table></div></div> - <hr/> - <div class="refsect2" lang="en"><h3><a name="virStoragePoolDefineXML"/>virStoragePoolDefineXML ()</h3><pre class="programlisting"><a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> virStoragePoolDefineXML (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * xml)<br/> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to hypervisor connection</td></tr><tr><td><span class="term"><i><tt>xmlDesc</tt></i>:</span></td><td>XML description for new pool</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td/></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>a <a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> object, or NULL if creation failed</td></tr></tbody></table></div></div> + <hr/> + <div class="refsect2" lang="en"><h3><a name="virStoragePoolDefineXML"/>virStoragePoolDefineXML ()</h3><pre class="programlisting"><a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> virStoragePoolDefineXML (<a href="libvirt-libvirt.html#virConnectPtr">virConnectPtr</a> conn, <br/> const char * xml, <br/> unsigned int flags)<br/> </pre><p>Define a new inactive storage pool based on its XML description. The pool is persitent, until explicitly undefined.</p> -<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to hypervisor connection</td></tr><tr><td><span class="term"><i><tt>xml</tt></i>:</span></td><td>XML description for new pool</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>a <a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> object, or NULL if creation failed</td></tr></tbody></table></div></div> +<div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>conn</tt></i>:</span></td><td>pointer to hypervisor connection</td></tr><tr><td><span class="term"><i><tt>xml</tt></i>:</span></td><td>XML description for new pool</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td/></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>a <a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> object, or NULL if creation failed</td></tr></tbody></table></div></div> <hr/> <div class="refsect2" lang="en"><h3><a name="virStoragePoolDelete"/>virStoragePoolDelete ()</h3><pre class="programlisting">int virStoragePoolDelete (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> unsigned int flags)<br/> -</pre><p>Delete the underlying pool resources. This is a non-recoverable operation.</p> +</pre><p>Delete the underlying pool resources. This is a non-recoverable operation. The <a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> object itself is not free'd.</p> <div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>pool</tt></i>:</span></td><td>pointer to storage pool</td></tr><tr><td><span class="term"><i><tt>flags</tt></i>:</span></td><td>flags for obliteration process</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, or -1 if it could not be obliterate</td></tr></tbody></table></div></div> <hr/> <div class="refsect2" lang="en"><h3><a name="virStoragePoolDestroy"/>virStoragePoolDestroy ()</h3><pre class="programlisting">int virStoragePoolDestroy (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool)<br/> -</pre><p>Destroy an active storage pool. The <a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> object should not be used after this method returns successfully as it has been free'd</p> +</pre><p>Destroy an active storage pool. This will deactivate the pool on the host, but keep any persistent config associated with it. If it has a persistent config it can later be restarted with virStoragePoolCreate(). This does not free the associated <a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> object.</p> <div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>pool</tt></i>:</span></td><td>pointer to storage pool</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, or -1 if it could not be destroyed</td></tr></tbody></table></div></div> <hr/> <div class="refsect2" lang="en"><h3><a name="virStoragePoolFree"/>virStoragePoolFree ()</h3><pre class="programlisting">int virStoragePoolFree (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool)<br/> -</pre><p>Free a storage pool object</p> +</pre><p>Free a storage pool object, releasing all memory associated with it. Does not change the state of the pool on the host.</p> <div class="variablelist"><table border="0"><col align="left"/><tbody><tr><td><span class="term"><i><tt>pool</tt></i>:</span></td><td>pointer to storage pool</td></tr><tr><td><span class="term"><i><tt>Returns</tt></i>:</span></td><td>0 on success, or -1 if it could not be free'd.</td></tr></tbody></table></div></div> <hr/> <div class="refsect2" lang="en"><h3><a name="virStoragePoolGetAutostart"/>virStoragePoolGetAutostart ()</h3><pre class="programlisting">int virStoragePoolGetAutostart (<a href="libvirt-libvirt.html#virStoragePoolPtr">virStoragePoolPtr</a> pool, <br/> int * autostart)<br/> diff -r d043e3715bce include/libvirt/virterror.h --- a/include/libvirt/virterror.h Tue Feb 19 16:26:35 2008 -0500 +++ b/include/libvirt/virterror.h Tue Feb 19 16:59:10 2008 -0500 @@ -136,6 +136,8 @@ typedef enum { VIR_ERR_INVALID_STORAGE_POOL, /* invalid storage pool object */ VIR_ERR_INVALID_STORAGE_VOL, /* invalid storage vol object */ VIR_WAR_NO_STORAGE, /* failed to start storage */ + VIR_ERR_NO_STORAGE_POOL, /* storage pool not found */ + VIR_ERR_NO_STORAGE_VOL, /* storage pool not found */ } virErrorNumber; /** diff -r d043e3715bce po/POTFILES.in --- a/po/POTFILES.in Tue Feb 19 16:26:35 2008 -0500 +++ b/po/POTFILES.in Tue Feb 19 16:59:10 2008 -0500 @@ -10,6 +10,9 @@ src/qemu_conf.c src/qemu_conf.c src/qemu_driver.c src/remote_internal.c +src/storage_backend.c +src/storage_conf.c +src/storage_driver.c src/sexpr.c src/test.c src/uuid.c diff -r d043e3715bce src/Makefile.am --- a/src/Makefile.am Tue Feb 19 16:26:35 2008 -0500 +++ b/src/Makefile.am Tue Feb 19 16:59:10 2008 -0500 @@ -58,6 +58,9 @@ CLIENT_SOURCES = \ openvz_conf.c openvz_conf.h \ openvz_driver.c openvz_driver.h \ nodeinfo.h nodeinfo.c \ + storage_conf.h storage_conf.c \ + storage_driver.h storage_driver.c \ + storage_backend.h storage_backend.c \ util.c util.h SERVER_SOURCES = \ diff -r d043e3715bce src/libvirt.c --- a/src/libvirt.c Tue Feb 19 16:26:35 2008 -0500 +++ b/src/libvirt.c Tue Feb 19 16:59:10 2008 -0500 @@ -37,6 +37,7 @@ #include "xen_unified.h" #include "remote_internal.h" #include "qemu_driver.h" +#include "storage_driver.h" #ifdef WITH_OPENVZ #include "openvz_driver.h" #endif @@ -215,6 +216,7 @@ virInitialize(void) #ifdef WITH_OPENVZ if (openvzRegister() == -1) return -1; #endif + if (storageRegister() == -1) return -1; #ifdef WITH_REMOTE if (remoteRegister () == -1) return -1; #endif diff -r d043e3715bce src/storage_backend.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_backend.c Tue Feb 19 16:59:10 2008 -0500 @@ -0,0 +1,88 @@ +/* + * storage_backend.h: internal storage driver backend contract + * + * Copyright (C) 2007-2008 Red Hat, Inc. + * Copyright (C) 2007-2008 Daniel P. Berrange + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> + */ + +#include <config.h> + +#include <string.h> +#include <regex.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "util.h" + +#include "storage_backend.h" + + +virStorageBackendPtr +virStorageBackendForType(int type) { + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, + _("missing backend for pool type %d"), type); + return NULL; +} + +virStorageBackendPoolOptionsPtr +virStorageBackendPoolOptionsForType(int type) { + virStorageBackendPtr backend = virStorageBackendForType(type); + if (backend == NULL) + return NULL; + return &backend->poolOptions; +} + +virStorageBackendVolOptionsPtr +virStorageBackendVolOptionsForType(int type) { + virStorageBackendPtr backend = virStorageBackendForType(type); + if (backend == NULL) + return NULL; + return &backend->volOptions; +} + + +int +virStorageBackendFromString(const char *type) { + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, + _("unknown storage backend type %s"), type); + return -1; +} + +const char * +virStorageBackendToString(int type) { + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, + _("unknown storage backend type %d"), type); + return NULL; +} + + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r d043e3715bce src/storage_backend.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_backend.h Tue Feb 19 16:59:10 2008 -0500 @@ -0,0 +1,121 @@ +/* + * storage_backend.h: internal storage driver backend contract + * + * Copyright (C) 2007-2008 Red Hat, Inc. + * Copyright (C) 2007-2008 Daniel P. Berrange + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> + */ + +#ifndef __VIR_STORAGE_BACKEND_H__ +#define __VIR_STORAGE_BACKEND_H__ + +#include <libvirt/libvirt.h> +#include "storage_conf.h" + + +typedef const char *(*virStorageVolFormatToString)(virConnectPtr conn, + int format); +typedef int (*virStorageVolFormatFromString)(virConnectPtr conn, + const char *format); + +typedef const char *(*virStoragePoolFormatToString)(virConnectPtr conn, + int format); +typedef int (*virStoragePoolFormatFromString)(virConnectPtr conn, + const char *format); + + +typedef struct _virStorageBackendVolOptions virStorageBackendVolOptions; +typedef virStorageBackendVolOptions *virStorageBackendVolOptionsPtr; +struct _virStorageBackendVolOptions { + virStorageVolFormatToString formatToString; + virStorageVolFormatFromString formatFromString; +}; + + +/* Flags to indicate mandatory components in the pool source */ +enum { + VIR_STORAGE_BACKEND_POOL_SOURCE_HOST = (1<<0), + VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE = (1<<1), + VIR_STORAGE_BACKEND_POOL_SOURCE_DIR = (1<<2), + VIR_STORAGE_BACKEND_POOL_SOURCE_ADAPTER = (1<<3), +}; + +typedef struct _virStorageBackendPoolOptions virStorageBackendPoolOptions; +typedef virStorageBackendPoolOptions *virStorageBackendPoolOptionsPtr; +struct _virStorageBackendPoolOptions { + int flags; + virStoragePoolFormatToString formatToString; + virStoragePoolFormatFromString formatFromString; +}; + +typedef int (*virStorageBackendStartPool)(virConnectPtr conn, virStoragePoolObjPtr pool); +typedef int (*virStorageBackendBuildPool)(virConnectPtr conn, virStoragePoolObjPtr pool, unsigned int flags); +typedef int (*virStorageBackendRefreshPool)(virConnectPtr conn, virStoragePoolObjPtr pool); +typedef int (*virStorageBackendStopPool)(virConnectPtr conn, virStoragePoolObjPtr pool); +typedef int (*virStorageBackendDeletePool)(virConnectPtr conn, virStoragePoolObjPtr pool, unsigned int flags); + +typedef int (*virStorageBackendCreateVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol); +typedef int (*virStorageBackendRefreshVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol); +typedef int (*virStorageBackendDeleteVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, unsigned int flags); + + +typedef struct _virStorageBackend virStorageBackend; +typedef virStorageBackend *virStorageBackendPtr; + +struct _virStorageBackend { + int type; + + virStorageBackendStartPool startPool; + virStorageBackendBuildPool buildPool; + virStorageBackendRefreshPool refreshPool; + virStorageBackendStopPool stopPool; + virStorageBackendDeletePool deletePool; + + virStorageBackendCreateVol createVol; + virStorageBackendRefreshVol refreshVol; + virStorageBackendDeleteVol deleteVol; + + virStorageBackendPoolOptions poolOptions; + virStorageBackendVolOptions volOptions; + + int volType; +}; + + +virStorageBackendPtr virStorageBackendForType(int type); +virStorageBackendPoolOptionsPtr virStorageBackendPoolOptionsForType(int type); +virStorageBackendVolOptionsPtr virStorageBackendVolOptionsForType(int type); +int virStorageBackendFromString(const char *type); +const char *virStorageBackendToString(int type); + + +#endif /* __VIR_STORAGE_BACKEND_H__ */ + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r d043e3715bce src/storage_conf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_conf.c Tue Feb 19 16:59:10 2008 -0500 @@ -0,0 +1,1251 @@ +/* + * storage_conf.c: config handling for storage driver + * + * Copyright (C) 2006-2008 Red Hat, Inc. + * Copyright (C) 2006-2008 Daniel P. Berrange + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> + */ + +#include <config.h> + +#include <libvirt/libvirt.h> +#include <libvirt/virterror.h> + +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/uri.h> + +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <fcntl.h> +#include <string.h> + +#include "storage_conf.h" +#include "storage_backend.h" +#include "xml.h" +#include "uuid.h" +#include "buf.h" +#include "util.h" + +#define virStorageLog(msg...) fprintf(stderr, msg) + +void +virStorageReportError(virConnectPtr conn, int code, const char *fmt, ...) { + va_list args; + char errorMessage[1024]; + + if (fmt) { + va_start(args, fmt); + vsnprintf(errorMessage, sizeof(errorMessage)-1, fmt, args); + va_end(args); + } else { + errorMessage[0] = '\0'; + } + virStorageLog("%s", errorMessage); + __virRaiseError(conn, NULL, NULL, VIR_FROM_STORAGE, code, VIR_ERR_ERROR, + NULL, NULL, NULL, -1, -1, "%s", errorMessage); +} + + + +void +virStorageVolDefFree(virStorageVolDefPtr def) { + int i; + free(def->name); + free(def->key); + + for (i = 0 ; i < def->source.nextent ; i++) { + free(def->source.extents[i].path); + } + free(def->source.extents); + + free(def->target.path); + free(def->target.perms.label); + free(def); +} + +void +virStoragePoolDefFree(virStoragePoolDefPtr def) { + int i; + + free(def->name); + free(def->source.host.name); + for (i = 0 ; i < def->source.ndevice ; i++) { + free(def->source.devices[i].freeExtents); + free(def->source.devices[i].path); + } + free(def->source.devices); + free(def->source.dir); + + if (def->source.authType == VIR_STORAGE_POOL_AUTH_CHAP) { + free(def->source.auth.chap.login); + free(def->source.auth.chap.passwd); + } + + free(def->target.path); + free(def->target.perms.label); + free(def); +} + + +void +virStoragePoolObjFree(virStoragePoolObjPtr obj) { + if (obj->def) + virStoragePoolDefFree(obj->def); + if (obj->newDef) + virStoragePoolDefFree(obj->newDef); + + free(obj->configFile); + free(obj->autostartLink); + free(obj); +} + +void +virStoragePoolObjRemove(virStorageDriverStatePtr driver, + virStoragePoolObjPtr pool) +{ + virStoragePoolObjPtr prev = NULL, curr; + + curr = driver->pools; + while (curr != pool) { + prev = curr; + curr = curr->next; + } + + if (curr) { + if (prev) + prev->next = curr->next; + else + driver->pools = curr->next; + + driver->ninactivePools--; + } + + virStoragePoolObjFree(pool); +} + + +static int +virStoragePoolDefParseAuthChap(virConnectPtr conn, + xmlXPathContextPtr ctxt, + virStoragePoolAuthChapPtr auth) { + auth->login = virXPathString("string(/pool/source/auth/@login)", ctxt); + if (auth->login == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("missing auth host attribute")); + return -1; + } + + auth->passwd = virXPathString("string(/pool/source/auth/@passwd)", ctxt); + if (auth->passwd == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("missing auth passwd attribute")); + return -1; + } + + return 0; +} + + +static int +virStoragePoolDefParsePerms(virConnectPtr conn, + xmlXPathContextPtr ctxt, + virStoragePermsPtr perms) { + char *mode; + long v; + + mode = virXPathString("string(/pool/permissions/mode)", ctxt); + if (!mode) { + perms->mode = 0700; + } else { + char *end; + perms->mode = strtol(mode, &end, 8); + if (*end || perms->mode < 0 || perms->mode > 0777) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("malformed octal mode")); + return -1; + } + } + + if (virXPathNode("/pool/permissions/owner", ctxt) == NULL) { + perms->uid = getuid(); + } else { + if (virXPathLong("number(/pool/permissions/owner)", ctxt, &v) < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("malformed owner element")); + return -1; + } + perms->uid = (int)v; + } + + if (virXPathNode("/pool/permissions/group", ctxt) == NULL) { + perms->uid = getgid(); + } else { + if (virXPathLong("number(/pool/permissions/group)", ctxt, &v) < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("malformed group element")); + return -1; + } + perms->gid = (int)v; + } + + /* NB, we're ignoring missing labels here - they'll simply inherit */ + perms->label = virXPathString("string(/pool/permissions/label)", ctxt); + + return 0; +} + + +static virStoragePoolDefPtr +virStoragePoolDefParseDoc(virConnectPtr conn, + xmlXPathContextPtr ctxt, + xmlNodePtr root) { + virStorageBackendPoolOptionsPtr options; + virStoragePoolDefPtr ret; + xmlChar *type = NULL; + char *uuid = NULL; + char *authType = NULL; + + if ((ret = calloc(1, sizeof(virStoragePoolDef))) == NULL) + return NULL; + + if (STRNEQ((const char *)root->name, "pool")) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("unknown root element")); + goto cleanup; + } + + type = xmlGetProp(root, BAD_CAST "type"); + if ((ret->type = virStorageBackendFromString((const char *)type)) < 0) + goto cleanup; + xmlFree(type); + type = NULL; + + if ((options = virStorageBackendPoolOptionsForType(ret->type)) == NULL) { + goto cleanup; + } + + if ((ret->name = virXPathString("string(/pool/name)", ctxt)) == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("missing name element")); + goto cleanup; + } + + uuid = virXPathString("string(/pool/uuid)", ctxt); + if (uuid == NULL) { + if (virUUIDGenerate(ret->uuid) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unable to generate uuid")); + goto cleanup; + } + } else { + if (virUUIDParse(uuid, ret->uuid) < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("malformed uuid element")); + goto cleanup; + } + free(uuid); + uuid = NULL; + } + + if (options->formatFromString) { + char *format = virXPathString("string(/pool/source/format/@type)", ctxt); + if ((ret->source.format = (options->formatFromString)(conn, format)) < 0) { + free(format); + goto cleanup; + } + free(format); + } + + if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_HOST) { + if ((ret->source.host.name = virXPathString("string(/pool/source/host/@name)", ctxt)) == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("missing source host name")); + goto cleanup; + } + } + if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE) { + xmlNodePtr *nodeset = NULL; + int nsource, i; + + if ((nsource = virXPathNodeSet("/pool/source/device", ctxt, &nodeset)) <= 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("cannot extract source devices")); + goto cleanup; + } + if ((ret->source.devices = calloc(nsource, sizeof(*ret->source.devices))) == NULL) { + free(nodeset); + virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("device")); + goto cleanup; + } + for (i = 0 ; i < nsource ; i++) { + xmlChar *path = xmlGetProp(nodeset[i], BAD_CAST "path"); + if (path == NULL) { + free(nodeset); + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("missing source device path")); + goto cleanup; + } + ret->source.devices[i].path = (char *)path; + } + free(nodeset); + ret->source.ndevice = nsource; + } + if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DIR) { + if ((ret->source.dir = virXPathString("string(/pool/source/dir/@path)", ctxt)) == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("missing source path")); + goto cleanup; + } + } + + + authType = virXPathString("string(/pool/source/auth/@type)", ctxt); + if (authType == NULL) { + ret->source.authType = VIR_STORAGE_POOL_AUTH_NONE; + } else { + if (STREQ(authType, "chap")) { + ret->source.authType = VIR_STORAGE_POOL_AUTH_CHAP; + } else { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("unknown auth type '%s'"), + (const char *)authType); + free(authType); + authType = NULL; + goto cleanup; + } + free(authType); + authType = NULL; + } + + if (ret->source.authType == VIR_STORAGE_POOL_AUTH_CHAP) { + if (virStoragePoolDefParseAuthChap(conn, ctxt, &ret->source.auth.chap) < 0) + goto cleanup; + } + + if ((ret->target.path = virXPathString("string(/pool/target/path)", ctxt)) == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("missing target path")); + goto cleanup; + } + + if (virStoragePoolDefParsePerms(conn, ctxt, &ret->target.perms) < 0) + goto cleanup; + + return ret; + + cleanup: + free(uuid); + if (type) + xmlFree(type); + virStoragePoolDefFree(ret); + return NULL; +} + +virStoragePoolDefPtr +virStoragePoolDefParse(virConnectPtr conn, + const char *xmlStr, + const char *filename) { + virStoragePoolDefPtr ret = NULL; + xmlDocPtr xml = NULL; + xmlNodePtr node = NULL; + xmlXPathContextPtr ctxt = NULL; + + if (!(xml = xmlReadDoc(BAD_CAST xmlStr, + filename ? filename : "storage.xml", + NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("malformed xml document")); + goto cleanup; + } + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, + _("xmlXPathContext")); + goto cleanup; + } + + node = xmlDocGetRootElement(xml); + if (node == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("missing root element")); + goto cleanup; + } + + ret = virStoragePoolDefParseDoc(conn, ctxt, node); + + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + + return ret; + + cleanup: + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + return NULL; +} + + +char * +virStoragePoolDefFormat(virConnectPtr conn, + virStoragePoolDefPtr def) { + virStorageBackendPoolOptionsPtr options; + virBufferPtr buf; + const char *type; + char uuid[VIR_UUID_STRING_BUFLEN]; + int i; + + options = virStorageBackendPoolOptionsForType(def->type); + if (options == NULL) + return NULL; + + if ((buf = virBufferNew(8192)) == NULL) + goto no_memory; + + type = virStorageBackendToString(def->type); + if (!type) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unexpected pool type")); + goto cleanup; + } + if (virBufferVSprintf(buf, "<pool type='%s'>\n", type) < 0) + goto no_memory; + + if (virBufferVSprintf(buf," <name>%s</name>\n", def->name) < 0) + goto no_memory; + + virUUIDFormat(def->uuid, uuid); + if (virBufferVSprintf(buf," <uuid>%s</uuid>\n", uuid) < 0) + goto no_memory; + + if (virBufferVSprintf(buf," <capacity>%llu</capacity>\n", + def->capacity) < 0) + goto no_memory; + if (virBufferVSprintf(buf," <allocation>%llu</allocation>\n", + def->allocation) < 0) + goto no_memory; + if (virBufferVSprintf(buf," <available>%llu</available>\n", + def->available) < 0) + goto no_memory; + + + if (virBufferAddLit(buf," <source>\n") < 0) + goto no_memory; + if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_HOST) && + def->source.host.name && + virBufferVSprintf(buf," <host name='%s'/>\n", def->source.host.name) < 0) + goto no_memory; + if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE) && + def->source.ndevice) { + for (i = 0 ; i < def->source.ndevice ; i++) { + if (virBufferVSprintf(buf," <device path='%s'>\n", def->source.devices[i].path) < 0) + goto no_memory; + if (def->source.devices[i].nfreeExtent) { + int j; + for (j = 0 ; j < def->source.devices[i].nfreeExtent ; j++) { + if (virBufferVSprintf(buf, " <freeExtent start='%llu' end='%llu'/>\n", + def->source.devices[i].freeExtents[j].start, + def->source.devices[i].freeExtents[j].end) < 0) + goto no_memory; + } + } + if (virBufferAddLit(buf," </device>\n") < 0) + goto no_memory; + } + } + if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DIR) && + def->source.dir && + virBufferVSprintf(buf," <directory path='%s'/>\n", def->source.dir) < 0) + goto no_memory; + if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_ADAPTER) && + def->source.adapter && + virBufferVSprintf(buf," <adapter name='%s'/>\n", def->source.adapter) < 0) + goto no_memory; + + if (options->formatToString) { + const char *format = (options->formatToString)(conn, def->source.format); + if (!format) + goto cleanup; + if (virBufferVSprintf(buf," <format type='%s'/>\n", format) < 0) + goto no_memory; + } + + + if (def->source.authType == VIR_STORAGE_POOL_AUTH_CHAP && + virBufferVSprintf(buf," <auth type='chap' login='%s' passwd='%s'>\n", + def->source.auth.chap.login, + def->source.auth.chap.passwd) < 0) + goto no_memory; + if (virBufferAddLit(buf," </source>\n") < 0) + goto no_memory; + + + + if (virBufferAddLit(buf," <target>\n") < 0) + goto no_memory; + + if (def->target.path && + virBufferVSprintf(buf," <path>%s</path>\n", def->target.path) < 0) + goto no_memory; + + if (virBufferAddLit(buf," <permissions>\n") < 0) + goto no_memory; + if (virBufferVSprintf(buf," <mode>0%o</mode>\n", + def->target.perms.mode) < 0) + goto no_memory; + if (virBufferVSprintf(buf," <owner>%d</owner>\n", + def->target.perms.uid) < 0) + goto no_memory; + if (virBufferVSprintf(buf," <group>%d</group>\n", + def->target.perms.gid) < 0) + goto no_memory; + + if (def->target.perms.label) { + if (virBufferVSprintf(buf," <label>%s</label>\n", + def->target.perms.label) < 0) + goto no_memory; + } + if (virBufferAddLit(buf," </permissions>\n") < 0) + goto no_memory; + if (virBufferAddLit(buf," </target>\n") < 0) + goto no_memory; + + if (virBufferAddLit(buf,"</pool>\n") < 0) + goto no_memory; + + return virBufferContentAndFree(buf); + + no_memory: + virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("xml")); + cleanup: + virBufferFree(buf); + return NULL; +} + + +static int +virStorageVolDefParsePerms(virConnectPtr conn, + xmlXPathContextPtr ctxt, + virStoragePermsPtr perms) { + char *mode; + long v; + + mode = virXPathString("string(/volume/permissions/mode)", ctxt); + if (!mode) { + perms->mode = 0600; + } else { + char *end = NULL; + perms->mode = strtol(mode, &end, 8); + if (*end || perms->mode < 0 || perms->mode > 0777) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("malformed octal mode")); + return -1; + } + } + + if (virXPathNode("/volume/permissions/owner", ctxt) == NULL) { + perms->uid = getuid(); + } else { + if (virXPathLong("number(/volume/permissions/owner)", ctxt, &v) < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("missing owner element")); + return -1; + } + perms->uid = (int)v; + } + if (virXPathNode("/volume/permissions/group", ctxt) == NULL) { + perms->gid = getgid(); + } else { + if (virXPathLong("number(/volume/permissions/group)", ctxt, &v) < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("missing owner element")); + return -1; + } + perms->gid = (int)v; + } + + /* NB, we're ignoring missing labels here - they'll simply inherit */ + perms->label = virXPathString("string(/volume/permissions/label)", ctxt); + + return 0; +} + + +static int +virStorageSize(virConnectPtr conn, + const char *unit, + const char *val, + unsigned long long *ret) { + unsigned long long mult; + char *end; + + if (!unit) { + mult = 1; + } else { + switch (unit[0]) { + case 'k': + case 'K': + mult = 1024ull; + break; + + case 'm': + case 'M': + mult = 1024ull * 1024ull; + break; + + case 'g': + case 'G': + mult = 1024ull * 1024ull * 1024ull; + break; + + case 't': + case 'T': + mult = 1024ull * 1024ull * 1024ull * 1024ull; + break; + + case 'p': + case 'P': + mult = 1024ull * 1024ull * 1024ull * 1024ull * 1024ull; + break; + + case 'y': + case 'Y': + mult = 1024ull * 1024ull * 1024ull * 1024ull * 1024ull * + 1024ull; + break; + + case 'z': + case 'Z': + mult = 1024ull * 1024ull * 1024ull * 1024ull * 1024ull * + 1024ull * 1024ull; + break; + + default: + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("unknown size units '%s'"), unit); + return -1; + } + } + + if (virStrToLong_ull (val, &end, 10, ret) < 0) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("malformed capacity element")); + return -1; + } + if (*ret > (ULLONG_MAX / mult)) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("capacity element value too large")); + return -1; + } + + *ret *= mult; + + return 0; +} + +static virStorageVolDefPtr +virStorageVolDefParseDoc(virConnectPtr conn, + virStoragePoolDefPtr pool, + xmlXPathContextPtr ctxt, + xmlNodePtr root) { + virStorageVolDefPtr ret; + virStorageBackendVolOptionsPtr options; + char *allocation = NULL; + char *capacity = NULL; + char *unit = NULL; + + options = virStorageBackendVolOptionsForType(pool->type); + if (options == NULL) + return NULL; + + if ((ret = calloc(1, sizeof(virStorageVolDef))) == NULL) + return NULL; + + if (STRNEQ((const char *)root->name, "volume")) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("unknown root element")); + goto cleanup; + } + + ret->name = virXPathString("string(/volume/name)", ctxt); + if (ret->name == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("missing name element")); + goto cleanup; + } + + /* Auto-generated so delibrately ignore */ + /*ret->key = virXPathString("string(/volume/key)", ctxt);*/ + + capacity = virXPathString("string(/volume/capacity)", ctxt); + unit = virXPathString("string(/volume/capacity/@unit)", ctxt); + if (capacity == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("missing capacity element")); + goto cleanup; + } + if (virStorageSize(conn, unit, capacity, &ret->capacity) < 0) + goto cleanup; + free(capacity); + capacity = NULL; + free(unit); + unit = NULL; + + allocation = virXPathString("string(/volume/allocation)", ctxt); + if (allocation) { + unit = virXPathString("string(/volume/allocation/@unit)", ctxt); + if (virStorageSize(conn, unit, allocation, &ret->allocation) < 0) + goto cleanup; + free(allocation); + allocation = NULL; + free(unit); + unit = NULL; + } else { + ret->allocation = ret->capacity; + } + + ret->target.path = virXPathString("string(/volume/target/path)", ctxt); + if (options->formatFromString) { + char *format = virXPathString("string(/volume/target/format/@type)", ctxt); + if ((ret->target.format = (options->formatFromString)(conn, format)) < 0) { + free(format); + goto cleanup; + } + free(format); + } + + if (virStorageVolDefParsePerms(conn, ctxt, &ret->target.perms) < 0) + goto cleanup; + + return ret; + + cleanup: + free(allocation); + free(capacity); + free(unit); + virStorageVolDefFree(ret); + return NULL; +} + + +virStorageVolDefPtr +virStorageVolDefParse(virConnectPtr conn, + virStoragePoolDefPtr pool, + const char *xmlStr, + const char *filename) { + virStorageVolDefPtr ret = NULL; + xmlDocPtr xml = NULL; + xmlNodePtr node = NULL; + xmlXPathContextPtr ctxt = NULL; + + if (!(xml = xmlReadDoc(BAD_CAST xmlStr, filename ? filename : "storage.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("malformed xml document")); + goto cleanup; + } + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, + _("xmlXPathContext")); + goto cleanup; + } + + node = xmlDocGetRootElement(xml); + if (node == NULL) { + virStorageReportError(conn, VIR_ERR_XML_ERROR, + _("missing root element")); + goto cleanup; + } + + ret = virStorageVolDefParseDoc(conn, pool, ctxt, node); + + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + + return ret; + + cleanup: + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + return NULL; +} + + + +char * +virStorageVolDefFormat(virConnectPtr conn, + virStoragePoolDefPtr pool, + virStorageVolDefPtr def) { + virStorageBackendVolOptionsPtr options; + virBufferPtr buf = virBufferNew(8192); + + options = virStorageBackendVolOptionsForType(pool->type); + if (options == NULL) + return NULL; + + if (!buf) + goto no_memory; + + if (virBufferAddLit(buf, "<volume>\n") < 0) + goto no_memory; + + if (virBufferVSprintf(buf," <name>%s</name>\n", def->name) < 0) + goto no_memory; + + if (virBufferVSprintf(buf," <key>%s</key>\n", def->key) < 0) + goto no_memory; + + if (virBufferAddLit(buf, " <source>\n") < 0) + goto no_memory; + if (def->source.nextent) { + int i; + const char *thispath = NULL; + for (i = 0 ; i < def->source.nextent ; i++) { + if (thispath == NULL || + STRNEQ(thispath, def->source.extents[i].path)) { + if (thispath != NULL) + if (virBufferAddLit(buf, " </device>\n") < 0) + goto no_memory; + if (virBufferVSprintf(buf, " <device path='%s'>\n", + def->source.extents[i].path) < 0) + goto no_memory; + } + + if (virBufferVSprintf(buf, + " <extent start='%llu' end='%llu'/>\n", + def->source.extents[i].start, + def->source.extents[i].end) < 0) + goto no_memory; + thispath = def->source.extents[i].path; + } + if (thispath != NULL) + if (virBufferAddLit(buf, " </device>\n") < 0) + goto no_memory; + } + if (virBufferAddLit(buf, " </source>\n") < 0) + goto no_memory; + + if (virBufferVSprintf(buf," <capacity>%llu</capacity>\n", + def->capacity) < 0) + goto no_memory; + if (virBufferVSprintf(buf," <allocation>%llu</allocation>\n", + def->allocation) < 0) + goto no_memory; + + if (virBufferAddLit(buf, " <target>\n") < 0) + goto no_memory; + + if (def->target.path && + virBufferVSprintf(buf," <path>%s</path>\n", def->target.path) < 0) + goto no_memory; + + if (options->formatToString) { + const char *format = (options->formatToString)(conn, + def->target.format); + if (!format) + goto cleanup; + if (virBufferVSprintf(buf," <format type='%s'/>\n", format) < 0) + goto no_memory; + } + + if (virBufferAddLit(buf," <permissions>\n") < 0) + goto no_memory; + if (virBufferVSprintf(buf," <mode>0%o</mode>\n", + def->target.perms.mode) < 0) + goto no_memory; + if (virBufferVSprintf(buf," <owner>%d</owner>\n", + def->target.perms.uid) < 0) + goto no_memory; + if (virBufferVSprintf(buf," <group>%d</group>\n", + def->target.perms.gid) < 0) + goto no_memory; + + if (def->target.perms.label && + virBufferVSprintf(buf," <label>%s</label>\n", + def->target.perms.label) < 0) + goto no_memory; + if (virBufferAddLit(buf," </permissions>\n") < 0) + goto no_memory; + + if (virBufferAddLit(buf, " </target>\n") < 0) + goto no_memory; + + if (virBufferAddLit(buf,"</volume>\n") < 0) + goto no_memory; + + return virBufferContentAndFree(buf); + + no_memory: + virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("xml")); + cleanup: + virBufferFree(buf); + return NULL; +} + + +virStoragePoolObjPtr +virStoragePoolObjFindByUUID(virStorageDriverStatePtr driver, + const unsigned char *uuid) { + virStoragePoolObjPtr pool = driver->pools; + + while (pool) { + if (!memcmp(pool->def->uuid, uuid, VIR_UUID_BUFLEN)) + return pool; + pool = pool->next; + } + + return NULL; +} + +virStoragePoolObjPtr +virStoragePoolObjFindByName(virStorageDriverStatePtr driver, + const char *name) { + virStoragePoolObjPtr pool = driver->pools; + + while (pool) { + if (STREQ(pool->def->name, name)) + return pool; + pool = pool->next; + } + + return NULL; +} + +void +virStoragePoolObjClearVols(virStoragePoolObjPtr pool) +{ + virStorageVolDefPtr vol = pool->volumes; + while (vol) { + virStorageVolDefPtr next = vol->next; + virStorageVolDefFree(vol); + vol = next; + } + pool->volumes = NULL; + pool->nvolumes = 0; +} + +virStorageVolDefPtr +virStorageVolDefFindByKey(virStoragePoolObjPtr pool, + const char *key) { + virStorageVolDefPtr vol = pool->volumes; + + while (vol) { + if (STREQ(vol->key, key)) + return vol; + vol = vol->next; + } + + return NULL; +} + +virStorageVolDefPtr +virStorageVolDefFindByPath(virStoragePoolObjPtr pool, + const char *path) { + virStorageVolDefPtr vol = pool->volumes; + + while (vol) { + if (STREQ(vol->target.path, path)) + return vol; + vol = vol->next; + } + + return NULL; +} + +virStorageVolDefPtr +virStorageVolDefFindByName(virStoragePoolObjPtr pool, + const char *name) { + virStorageVolDefPtr vol = pool->volumes; + + while (vol) { + if (STREQ(vol->name, name)) + return vol; + vol = vol->next; + } + + return NULL; +} + +virStoragePoolObjPtr +virStoragePoolObjAssignDef(virConnectPtr conn, + virStorageDriverStatePtr driver, + virStoragePoolDefPtr def) { + virStoragePoolObjPtr pool; + + if ((pool = virStoragePoolObjFindByName(driver, def->name))) { + if (!virStoragePoolObjIsActive(pool)) { + virStoragePoolDefFree(pool->def); + pool->def = def; + } else { + if (pool->newDef) + virStoragePoolDefFree(pool->newDef); + pool->newDef = def; + } + return pool; + } + + if (!(pool = calloc(1, sizeof(virStoragePoolObj)))) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, + _("pool")); + return NULL; + } + + pool->active = 0; + pool->def = def; + pool->next = driver->pools; + + driver->pools = pool; + driver->ninactivePools++; + + return pool; +} + +static virStoragePoolObjPtr +virStoragePoolObjLoad(virStorageDriverStatePtr driver, + const char *file, + const char *path, + const char *xml, + const char *autostartLink) { + virStoragePoolDefPtr def; + virStoragePoolObjPtr pool; + + if (!(def = virStoragePoolDefParse(NULL, xml, file))) { + virErrorPtr err = virGetLastError(); + virStorageLog("Error parsing storage pool config '%s' : %s", + path, err->message); + return NULL; + } + + if (!virFileMatchesNameSuffix(file, def->name, ".xml")) { + virStorageLog("Storage pool config filename '%s' does not match pool name '%s'", + path, def->name); + virStoragePoolDefFree(def); + return NULL; + } + + if (!(pool = virStoragePoolObjAssignDef(NULL, driver, def))) { + virStorageLog("Failed to load storage pool config '%s': out of memory", path); + virStoragePoolDefFree(def); + return NULL; + } + + pool->configFile = strdup(path); + if (pool->configFile == NULL) { + virStorageLog("Failed to load storage pool config '%s': out of memory", path); + virStoragePoolDefFree(def); + return NULL; + } + pool->autostartLink = strdup(autostartLink); + if (pool->autostartLink == NULL) { + virStorageLog("Failed to load storage pool config '%s': out of memory", path); + virStoragePoolDefFree(def); + return NULL; + } + + pool->autostart = virFileLinkPointsTo(pool->autostartLink, + pool->configFile); + + return pool; +} + + +int +virStoragePoolObjScanConfigs(virStorageDriverStatePtr driver) { + DIR *dir; + struct dirent *entry; + + if (!(dir = opendir(driver->configDir))) { + if (errno == ENOENT) + return 0; + virStorageLog("Failed to open dir '%s': %s", + driver->configDir, strerror(errno)); + return -1; + } + + while ((entry = readdir(dir))) { + char *xml = NULL; + char path[PATH_MAX]; + char autostartLink[PATH_MAX]; + + if (entry->d_name[0] == '.') + continue; + + if (!virFileHasSuffix(entry->d_name, ".xml")) + continue; + + if (virFileBuildPath(driver->configDir, entry->d_name, + NULL, path, PATH_MAX) < 0) { + virStorageLog("Config filename '%s/%s' is too long", + driver->configDir, entry->d_name); + continue; + } + + if (virFileBuildPath(driver->autostartDir, entry->d_name, + NULL, autostartLink, PATH_MAX) < 0) { + virStorageLog("Autostart link path '%s/%s' is too long", + driver->autostartDir, entry->d_name); + continue; + } + + if (virFileReadAll(path, 8192, &xml) < 0) + continue; + + virStoragePoolObjLoad(driver, entry->d_name, path, xml, autostartLink); + + free(xml); + } + + closedir(dir); + + return 0; +} + +int +virStoragePoolObjSaveDef(virConnectPtr conn, + virStorageDriverStatePtr driver, + virStoragePoolObjPtr pool, + virStoragePoolDefPtr def) { + char *xml; + int fd = -1, ret = -1; + ssize_t towrite; + + if (!pool->configFile) { + int err; + char path[PATH_MAX]; + + if ((err = virFileMakePath(driver->configDir))) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot create config directory %s: %s"), + driver->configDir, strerror(err)); + return -1; + } + + if (virFileBuildPath(driver->configDir, def->name, ".xml", + path, sizeof(path)) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot construct config file path")); + return -1; + } + if (!(pool->configFile = strdup(path))) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, + _("configFile")); + return -1; + } + + if (virFileBuildPath(driver->autostartDir, def->name, ".xml", + path, sizeof(path)) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot construct autostart link path")); + free(pool->configFile); + pool->configFile = NULL; + return -1; + } + if (!(pool->autostartLink = strdup(path))) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, + _("config file")); + free(pool->configFile); + pool->configFile = NULL; + return -1; + } + } + + if (!(xml = virStoragePoolDefFormat(conn, def))) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("failed to generate XML")); + return -1; + } + + if ((fd = open(pool->configFile, + O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR )) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot create config file %s: %s"), + pool->configFile, strerror(errno)); + goto cleanup; + } + + towrite = strlen(xml); + if (safewrite(fd, xml, towrite) != towrite) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot write config file %s: %s"), + pool->configFile, strerror(errno)); + goto cleanup; + } + + if (close(fd) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot save config file %s: %s"), + pool->configFile, strerror(errno)); + goto cleanup; + } + + ret = 0; + + cleanup: + if (fd != -1) + close(fd); + + free(xml); + + return ret; +} + +int +virStoragePoolObjDeleteDef(virConnectPtr conn, + virStoragePoolObjPtr pool) { + if (!pool->configFile) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("no config file for %s"), pool->def->name); + return -1; + } + + if (unlink(pool->configFile) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot remove config for %s"), + pool->def->name); + return -1; + } + + return 0; +} + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r d043e3715bce src/storage_conf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_conf.h Tue Feb 19 16:59:10 2008 -0500 @@ -0,0 +1,314 @@ +/* + * storage_conf.h: config handling for storage driver + * + * Copyright (C) 2006-2008 Red Hat, Inc. + * Copyright (C) 2006-2008 Daniel P. Berrange + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> + */ + +#ifndef __VIR_STORAGE_CONF_H__ +#define __VIR_STORAGE_CONF_H__ + +#include <libvirt/libvirt.h> +#include "internal.h" + +/* Shared structs */ + + + +typedef struct _virStoragePerms virStoragePerms; +typedef virStoragePerms *virStoragePermsPtr; +struct _virStoragePerms { + int mode; + int uid; + int gid; + char *label; +}; + +/* Storage volumes */ + + +/* + * How the volume's data is stored on underlying + * physical devices - can potentially span many + * devices in LVM case. + */ +typedef struct _virStorageVolSourceExtent virStorageVolSourceExtent; +typedef virStorageVolSourceExtent *virStorageVolSourceExtentPtr; +struct _virStorageVolSourceExtent { + char *path; + unsigned long long start; + unsigned long long end; +}; + +typedef struct _virStorageVolSource virStorageVolSource; +typedef virStorageVolSource *virStorageVolSourcePtr; +struct _virStorageVolSource { + int nextent; + virStorageVolSourceExtentPtr extents; +}; + + +/* + * How the volume appears on the host + */ +typedef struct _virStorageVolTarget virStorageVolTarget; +typedef virStorageVolTarget *virStorageVolTargetPtr; +struct _virStorageVolTarget { + char *path; + int format; + virStoragePerms perms; +}; + + +typedef struct _virStorageVolDef virStorageVolDef; +typedef virStorageVolDef *virStorageVolDefPtr; +struct _virStorageVolDef { + char *name; + char *key; + + unsigned long long allocation; + unsigned long long capacity; + + virStorageVolSource source; + virStorageVolTarget target; + + virStorageVolDefPtr next; +}; + + + + +/* Storage pools */ + +enum virStoragePoolType { + VIR_STORAGE_POOL_DIR = 1, /* Local directory */ + VIR_STORAGE_POOL_FS, /* Local filesystem */ + VIR_STORAGE_POOL_NETFS, /* Networked filesystem - eg NFS, GFS, etc */ + VIR_STORAGE_POOL_LOGICAL, /* Logical volume groups / volumes */ + VIR_STORAGE_POOL_DISK, /* Disk partitions */ + VIR_STORAGE_POOL_ISCSI, /* iSCSI targets */ + VIR_STORAGE_POOL_SCSI, /* SCSI HBA */ +}; + + +enum virStoragePoolAuthType { + VIR_STORAGE_POOL_AUTH_NONE, + VIR_STORAGE_POOL_AUTH_CHAP, +}; + +typedef struct _virStoragePoolAuthChap virStoragePoolAuthChap; +typedef virStoragePoolAuthChap *virStoragePoolAuthChapPtr; +struct _virStoragePoolAuthChap { + char *login; + char *passwd; +}; + + +/* + * For remote pools, info on how to reach the host + */ +typedef struct _virStoragePoolSourceHost virStoragePoolSourceHost; +typedef virStoragePoolSourceHost *virStoragePoolSourceHostPtr; +struct _virStoragePoolSourceHost { + char *name; + int port; + int protocol; +}; + + +/* + * Available extents on the underlying storage + */ +typedef struct _virStoragePoolSourceDeviceExtent virStoragePoolSourceDeviceExtent; +typedef virStoragePoolSourceDeviceExtent *virStoragePoolSourceDeviceExtentPtr; +struct _virStoragePoolSourceDeviceExtent { + unsigned long long start; + unsigned long long end; +}; + + +/* + * Pools can be backed by one or more devices, and some + * allow us to track free space on underlying devices. + */ +typedef struct _virStoragePoolSourceDevice virStoragePoolSourceDevice; +typedef virStoragePoolSourceDevice *virStoragePoolSourceDevicePtr; +struct _virStoragePoolSourceDevice { + int nfreeExtent; + virStoragePoolSourceDeviceExtentPtr freeExtents; + char *path; + int format; /* Pool specific source format */ +}; + + + +typedef struct _virStoragePoolSource virStoragePoolSource; +typedef virStoragePoolSource *virStoragePoolSourcePtr; +struct _virStoragePoolSource { + /* An optional host */ + virStoragePoolSourceHost host; + + /* And either one or more devices ... */ + int ndevice; + virStoragePoolSourceDevicePtr devices; + + /* Or a directory */ + char *dir; + + /* Or an adapter */ + char *adapter; + + int authType; /* virStoragePoolAuthType */ + union { + virStoragePoolAuthChap chap; + } auth; + + int format; /* Pool type specific format such as filesystem type, or lvm version, etc */ +}; + + +typedef struct _virStoragePoolTarget virStoragePoolTarget; +typedef virStoragePoolTarget *virStoragePoolTargetPtr; +struct _virStoragePoolTarget { + char *path; /* Optional local filesystem mapping */ + virStoragePerms perms; /* Default permissions for volumes */ +}; + + +typedef struct _virStoragePoolDef virStoragePoolDef; +typedef virStoragePoolDef *virStoragePoolDefPtr; +struct _virStoragePoolDef { + /* General metadata */ + char *name; + unsigned char uuid[VIR_UUID_BUFLEN]; + int type; /* virStoragePoolType */ + + unsigned long long allocation; + unsigned long long capacity; + unsigned long long available; + + virStoragePoolSource source; + virStoragePoolTarget target; +}; + +typedef struct _virStoragePoolObj virStoragePoolObj; +typedef virStoragePoolObj *virStoragePoolObjPtr; + +struct _virStoragePoolObj { + char *configFile; + char *autostartLink; + int active; + int autostart; + + virStoragePoolDefPtr def; + virStoragePoolDefPtr newDef; + + int nvolumes; + virStorageVolDefPtr volumes; + + virStoragePoolObjPtr next; +}; + + + + +typedef struct _virStorageDriverState virStorageDriverState; +typedef virStorageDriverState *virStorageDriverStatePtr; + +struct _virStorageDriverState { + int nactivePools; + int ninactivePools; + virStoragePoolObjPtr pools; + char *configDir; + char *autostartDir; +}; + + +static inline int virStoragePoolObjIsActive(virStoragePoolObjPtr pool) { + return pool->active; +} + +void virStorageReportError(virConnectPtr conn, + int code, + const char *fmt, ...) + ATTRIBUTE_FORMAT(printf, 3, 4); + +int virStoragePoolObjScanConfigs(virStorageDriverStatePtr driver); + +virStoragePoolObjPtr virStoragePoolObjFindByUUID(virStorageDriverStatePtr driver, + const unsigned char *uuid); +virStoragePoolObjPtr virStoragePoolObjFindByName(virStorageDriverStatePtr driver, + const char *name); + +virStorageVolDefPtr virStorageVolDefFindByKey(virStoragePoolObjPtr pool, + const char *key); +virStorageVolDefPtr virStorageVolDefFindByPath(virStoragePoolObjPtr pool, + const char *path); +virStorageVolDefPtr virStorageVolDefFindByName(virStoragePoolObjPtr pool, + const char *name); + +void virStoragePoolObjClearVols(virStoragePoolObjPtr pool); + +virStoragePoolDefPtr virStoragePoolDefParse(virConnectPtr conn, + const char *xml, + const char *filename); +char *virStoragePoolDefFormat(virConnectPtr conn, + virStoragePoolDefPtr def); + +virStorageVolDefPtr virStorageVolDefParse(virConnectPtr conn, + virStoragePoolDefPtr pool, + const char *xml, + const char *filename); +char *virStorageVolDefFormat(virConnectPtr conn, + virStoragePoolDefPtr pool, + virStorageVolDefPtr def); + +virStoragePoolObjPtr virStoragePoolObjAssignDef(virConnectPtr conn, + virStorageDriverStatePtr driver, + virStoragePoolDefPtr def); + +int virStoragePoolObjSaveDef(virConnectPtr conn, + virStorageDriverStatePtr driver, + virStoragePoolObjPtr pool, + virStoragePoolDefPtr def); +int virStoragePoolObjDeleteDef(virConnectPtr conn, + virStoragePoolObjPtr pool); + +void virStorageVolDefFree(virStorageVolDefPtr def); +void virStoragePoolDefFree(virStoragePoolDefPtr def); +void virStoragePoolObjFree(virStoragePoolObjPtr pool); +void virStoragePoolObjRemove(virStorageDriverStatePtr driver, + virStoragePoolObjPtr pool); + +#endif /* __VIR_STORAGE_DRIVER_H__ */ + + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r d043e3715bce src/storage_driver.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_driver.c Tue Feb 19 16:59:10 2008 -0500 @@ -0,0 +1,1261 @@ +/* + * storage_driver.c: core driver for storage APIs + * + * Copyright (C) 2006-2008 Red Hat, Inc. + * Copyright (C) 2006-2008 Daniel P. Berrange + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> + */ + +#include <config.h> + +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <pwd.h> +#include <errno.h> +#include <string.h> + +#include "driver.h" +#include "util.h" +#include "storage_driver.h" +#include "storage_conf.h" + +#include "storage_backend.h" + +#define storageLog(msg...) fprintf(stderr, msg) + +static virStorageDriverStatePtr driverState; + +static int storageDriverShutdown(void); + + +static void +storageDriverAutostart(virStorageDriverStatePtr driver) { + virStoragePoolObjPtr pool; + + pool = driver->pools; + while (pool != NULL) { + virStoragePoolObjPtr next = pool->next; + + if (pool->autostart && + !virStoragePoolObjIsActive(pool)) { + virStorageBackendPtr backend; + if ((backend = virStorageBackendForType(pool->def->type)) == NULL) { + storageLog("Missing backend %d", + pool->def->type); + pool = next; + continue; + } + + if (backend->startPool && + backend->startPool(NULL, pool) < 0) { + virErrorPtr err = virGetLastError(); + storageLog("Failed to autostart storage pool '%s': %s", + pool->def->name, err ? err->message : NULL); + pool = next; + continue; + } + + if (backend->refreshPool(NULL, pool) < 0) { + virErrorPtr err = virGetLastError(); + if (backend->stopPool) + backend->stopPool(NULL, pool); + storageLog("Failed to autostart storage pool '%s': %s", + pool->def->name, err ? err->message : NULL); + pool = next; + continue; + } + pool->active = 1; + driver->nactivePools++; + driver->ninactivePools--; + } + + pool = next; + } +} + +/** + * virStorageStartup: + * + * Initialization function for the QEmu daemon + */ +static int +storageDriverStartup(void) { + uid_t uid = geteuid(); + struct passwd *pw; + char *base = NULL; + char driverConf[PATH_MAX]; + + if (!(driverState = calloc(1, sizeof(virStorageDriverState)))) { + return -1; + } + + if (!uid) { + if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL) + goto out_of_memory; + } else { + if (!(pw = getpwuid(uid))) { + storageLog("Failed to find user record for uid '%d': %s", + uid, strerror(errno)); + goto out_of_memory; + } + + if (asprintf (&base, "%s/.libvirt", pw->pw_dir) == -1) { + storageLog("out of memory in asprintf"); + goto out_of_memory; + } + } + + /* Configuration paths are either ~/.libvirt/storage/... (session) or + * /etc/libvirt/storage/... (system). + */ + if (snprintf (driverConf, sizeof(driverConf), + "%s/storage.conf", base) == -1) + goto out_of_memory; + driverConf[sizeof(driverConf)-1] = '\0'; + + if (asprintf (&driverState->configDir, + "%s/storage", base) == -1) + goto out_of_memory; + + if (asprintf (&driverState->autostartDir, + "%s/storage/autostart", base) == -1) + goto out_of_memory; + + free(base); + base = NULL; + + /* + if (virStorageLoadDriverConfig(driver, driverConf) < 0) { + virStorageDriverShutdown(); + return -1; + } + */ + + if (virStoragePoolObjScanConfigs(driverState) < 0) { + storageDriverShutdown(); + return -1; + } + storageDriverAutostart(driverState); + + return 0; + + out_of_memory: + storageLog("virStorageStartup: out of memory"); + free(base); + free(driverState); + driverState = NULL; + return -1; +} + +/** + * virStorageReload: + * + * Function to restart the storage driver, it will recheck the configuration + * files and update its state + */ +static int +storageDriverReload(void) { + virStoragePoolObjScanConfigs(driverState); + storageDriverAutostart(driverState); + + return 0; +} + +/** + * virStorageActive: + * + * Checks if the storage driver is active, i.e. has an active pool + * + * Returns 1 if active, 0 otherwise + */ +static int +storageDriverActive(void) { + /* If we've any active networks or guests, then we + * mark this driver as active + */ + if (driverState->nactivePools) + return 1; + + /* Otherwise we're happy to deal with a shutdown */ + return 0; +} + +/** + * virStorageShutdown: + * + * Shutdown the storage driver, it will stop all active storage pools + */ +static int +storageDriverShutdown(void) { + virStoragePoolObjPtr pool; + + if (!driverState) + return -1; + + /* shutdown active pools */ + pool = driverState->pools; + while (pool) { + virStoragePoolObjPtr next = pool->next; + if (virStoragePoolObjIsActive(pool)) { + virStorageBackendPtr backend; + if ((backend = virStorageBackendForType(pool->def->type)) == NULL) { + storageLog("Missing backend"); + continue; + } + + if (backend->stopPool && + backend->stopPool(NULL, pool) < 0) { + virErrorPtr err = virGetLastError(); + storageLog("Failed to stop storage pool '%s': %s", + pool->def->name, err->message); + } + virStoragePoolObjClearVols(pool); + } + pool = next; + } + + /* free inactive pools */ + pool = driverState->pools; + while (pool) { + virStoragePoolObjPtr next = pool->next; + virStoragePoolObjFree(pool); + pool = next; + } + driverState->pools = NULL; + driverState->nactivePools = 0; + driverState->ninactivePools = 0; + + free(driverState->configDir); + free(driverState->autostartDir); + free(driverState); + driverState = NULL; + + return 0; +} + + + +static virStoragePoolPtr +storagePoolLookupByUUID(virConnectPtr conn, + const unsigned char *uuid) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, uuid); + virStoragePoolPtr ret; + + if (!pool) { + virStorageReportError(conn, VIR_ERR_NO_STORAGE_POOL, + _("no pool with matching uuid")); + return NULL; + } + + ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid); + return ret; +} + +static virStoragePoolPtr +storagePoolLookupByName(virConnectPtr conn, + const char *name) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByName(driver, name); + virStoragePoolPtr ret; + + if (!pool) { + virStorageReportError(conn, VIR_ERR_NO_STORAGE_POOL, + _("no pool with matching name")); + return NULL; + } + + ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid); + return ret; +} + +static virStoragePoolPtr +storagePoolLookupByVolume(virStorageVolPtr vol) { + return storagePoolLookupByName(vol->conn, vol->pool); +} + +static virDrvOpenStatus +storageOpen(virConnectPtr conn, + xmlURIPtr uri ATTRIBUTE_UNUSED, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) { + if (!driverState) + return VIR_DRV_OPEN_DECLINED; + + conn->storagePrivateData = driverState; + return VIR_DRV_OPEN_SUCCESS; +} + +static int +storageClose(virConnectPtr conn) { + conn->storagePrivateData = NULL; + return 0; +} + +static int +storageNumPools(virConnectPtr conn) { + virStorageDriverStatePtr driver + = (virStorageDriverStatePtr)conn->storagePrivateData; + return driver->nactivePools; +} + +static int +storageListPools(virConnectPtr conn, + char **const names, + int nnames) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)conn->storagePrivateData; + virStoragePoolObjPtr pool = driver->pools; + int got = 0, i; + while (pool && got < nnames) { + if (virStoragePoolObjIsActive(pool)) { + if (!(names[got] = strdup(pool->def->name))) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, + _("names")); + goto cleanup; + } + got++; + } + pool = pool->next; + } + return got; + + cleanup: + for (i = 0 ; i < got ; i++) { + free(names[i]); + names[i] = NULL; + } + memset(names, 0, nnames); + return -1; +} + +static int +storageNumDefinedPools(virConnectPtr conn) { + virStorageDriverStatePtr driver + = (virStorageDriverStatePtr)conn->storagePrivateData; + return driver->ninactivePools; +} + +static int +storageListDefinedPools(virConnectPtr conn, + char **const names, + int nnames) { + virStorageDriverStatePtr driver + = (virStorageDriverStatePtr)conn->storagePrivateData; + virStoragePoolObjPtr pool = driver->pools; + int got = 0, i; + while (pool && got < nnames) { + if (!virStoragePoolObjIsActive(pool)) { + if (!(names[got] = strdup(pool->def->name))) { + virStorageReportError(conn, VIR_ERR_NO_MEMORY, + _("names")); + goto cleanup; + } + got++; + } + pool = pool->next; + } + return got; + + cleanup: + for (i = 0 ; i < got ; i++) { + free(names[i]); + names[i] = NULL; + } + memset(names, 0, nnames); + return -1; +} + +static virStoragePoolPtr +storagePoolCreate(virConnectPtr conn, + const char *xml, + unsigned int flags ATTRIBUTE_UNUSED) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr )conn->storagePrivateData; + virStoragePoolDefPtr def; + virStoragePoolObjPtr pool; + virStoragePoolPtr ret; + virStorageBackendPtr backend; + + if (!(def = virStoragePoolDefParse(conn, xml, NULL))) + return NULL; + + if (virStoragePoolObjFindByUUID(driver, def->uuid) || + virStoragePoolObjFindByName(driver, def->name)) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("storage pool already exists")); + virStoragePoolDefFree(def); + return NULL; + } + + if ((backend = virStorageBackendForType(def->type)) == NULL) { + virStoragePoolDefFree(def); + return NULL; + } + + if (!(pool = virStoragePoolObjAssignDef(conn, driver, def))) { + virStoragePoolDefFree(def); + return NULL; + } + + if (backend->startPool(conn, pool) < 0) { + virStoragePoolObjRemove(driver, pool); + return NULL; + } + pool->active = 1; + driver->nactivePools++; + driver->ninactivePools--; + + ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid); + + return ret; +} + +static virStoragePoolPtr +storagePoolDefine(virConnectPtr conn, + const char *xml, + unsigned int flags ATTRIBUTE_UNUSED) { + virStorageDriverStatePtr driver + = (virStorageDriverStatePtr )conn->storagePrivateData; + virStoragePoolDefPtr def; + virStoragePoolObjPtr pool; + virStoragePoolPtr ret; + virStorageBackendPtr backend; + + if (!(def = virStoragePoolDefParse(conn, xml, NULL))) + return NULL; + + if ((backend = virStorageBackendForType(def->type)) == NULL) { + virStoragePoolDefFree(def); + return NULL; + } + + if (!(pool = virStoragePoolObjAssignDef(conn, driver, def))) { + virStoragePoolDefFree(def); + return NULL; + } + + if (virStoragePoolObjSaveDef(conn, driver, pool, def) < 0) { + virStoragePoolObjRemove(driver, pool); + return NULL; + } + + ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid); + return ret; +} + +static int +storagePoolUndefine(virStoragePoolPtr obj) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return -1; + } + + if (virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("pool is still active")); + return -1; + } + + if (virStoragePoolObjDeleteDef(obj->conn, pool) < 0) + return -1; + + if (unlink(pool->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) + storageLog("Failed to delete autostart link '%s': %s", + pool->autostartLink, strerror(errno)); + + free(pool->configFile); + pool->configFile = NULL; + free(pool->autostartLink); + pool->autostartLink = NULL; + + virStoragePoolObjRemove(driver, pool); + + return 0; +} + +static int +storagePoolStart(virStoragePoolPtr obj, + unsigned int flags ATTRIBUTE_UNUSED) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStorageBackendPtr backend; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return -1; + } + + if ((backend = virStorageBackendForType(pool->def->type)) == NULL) { + return -1; + } + + if (virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("pool already active")); + return -1; + } + if (backend->startPool && + backend->startPool(obj->conn, pool) < 0) + return -1; + if (backend->refreshPool(obj->conn, pool) < 0) { + if (backend->stopPool) + backend->stopPool(obj->conn, pool); + return -1; + } + + pool->active = 1; + driver->nactivePools++; + driver->ninactivePools--; + + return 0; +} + +static int +storagePoolBuild(virStoragePoolPtr obj, + unsigned int flags) { + virStorageDriverStatePtr driver + = (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStorageBackendPtr backend; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return -1; + } + + if ((backend = virStorageBackendForType(pool->def->type)) == NULL) { + return -1; + } + + if (virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("storage pool is already active")); + return -1; + } + + if (backend->buildPool && + backend->buildPool(obj->conn, pool, flags) < 0) + return -1; + + return 0; +} + + +static int +storagePoolDestroy(virStoragePoolPtr obj) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStorageBackendPtr backend; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return -1; + } + + if ((backend = virStorageBackendForType(pool->def->type)) == NULL) { + return -1; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("storage pool is not active")); + return -1; + } + + if (backend->stopPool && + backend->stopPool(obj->conn, pool) < 0) + return -1; + + virStoragePoolObjClearVols(pool); + + pool->active = 0; + driver->nactivePools--; + driver->ninactivePools++; + + if (pool->configFile == NULL) + virStoragePoolObjRemove(driver, pool); + + return 0; +} + + +static int +storagePoolDelete(virStoragePoolPtr obj, + unsigned int flags) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStorageBackendPtr backend; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return -1; + } + + if ((backend = virStorageBackendForType(pool->def->type)) == NULL) { + return -1; + } + + if (virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("storage pool is still active")); + return -1; + } + + if (!backend->deletePool) { + virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT, + _("pool does not support volume delete")); + return -1; + } + if (backend->deletePool(obj->conn, pool, flags) < 0) + return -1; + + return 0; +} + + +static int +storagePoolRefresh(virStoragePoolPtr obj, + unsigned int flags ATTRIBUTE_UNUSED) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStorageBackendPtr backend; + int ret = 0; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return -1; + } + + if ((backend = virStorageBackendForType(pool->def->type)) == NULL) { + return -1; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("storage pool is not active")); + return -1; + } + + virStoragePoolObjClearVols(pool); + if ((ret = backend->refreshPool(obj->conn, pool)) < 0) { + if (backend->stopPool) + backend->stopPool(obj->conn, pool); + + pool->active = 0; + driver->nactivePools--; + driver->ninactivePools++; + + if (pool->configFile == NULL) + virStoragePoolObjRemove(driver, pool); + } + + return ret; +} + + +static int +storagePoolGetInfo(virStoragePoolPtr obj, + virStoragePoolInfoPtr info) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStorageBackendPtr backend; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return -1; + } + + if ((backend = virStorageBackendForType(pool->def->type)) == NULL) { + return -1; + } + + memset(info, 0, sizeof(virStoragePoolInfo)); + if (pool->active) + info->state = VIR_STORAGE_POOL_RUNNING; + else + info->state = VIR_STORAGE_POOL_INACTIVE; + info->capacity = pool->def->capacity; + info->allocation = pool->def->allocation; + info->available = pool->def->available; + + return 0; +} + +static char * +storagePoolDumpXML(virStoragePoolPtr obj, + unsigned int flags ATTRIBUTE_UNUSED) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return NULL; + } + + return virStoragePoolDefFormat(obj->conn, pool->def); +} + +static int +storagePoolGetAutostart(virStoragePoolPtr obj, + int *autostart) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no pool with matching uuid")); + return -1; + } + + if (!pool->configFile) { + *autostart = 0; + } else { + *autostart = pool->autostart; + } + + return 0; +} + +static int +storagePoolSetAutostart(virStoragePoolPtr obj, + int autostart) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no pool with matching uuid")); + return -1; + } + + if (!pool->configFile) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_ARG, + _("pool has no config file")); + return -1; + } + + autostart = (autostart != 0); + + if (pool->autostart == autostart) + return 0; + + if (autostart) { + int err; + + if ((err = virFileMakePath(driver->autostartDir))) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("cannot create autostart directory %s: %s"), + driver->autostartDir, strerror(err)); + return -1; + } + + if (symlink(pool->configFile, pool->autostartLink) < 0) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("Failed to create symlink '%s' to '%s': %s"), + pool->autostartLink, pool->configFile, + strerror(errno)); + return -1; + } + } else { + if (unlink(pool->autostartLink) < 0 && + errno != ENOENT && errno != ENOTDIR) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("Failed to delete symlink '%s': %s"), + pool->autostartLink, strerror(errno)); + return -1; + } + } + + pool->autostart = autostart; + + return 0; +} + + +static int +storagePoolNumVolumes(virStoragePoolPtr obj) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return -1; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("storage pool is not active")); + return -1; + } + + return pool->nvolumes; +} + +static int +storagePoolListVolumes(virStoragePoolPtr obj, + char **const names, + int maxnames) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + int i = 0; + virStorageVolDefPtr vol; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return -1; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("storage pool is not active")); + return -1; + } + + memset(names, 0, maxnames); + vol = pool->volumes; + while (vol && i < maxnames) { + names[i] = strdup(vol->name); + if (names[i] == NULL) { + virStorageReportError(obj->conn, VIR_ERR_NO_MEMORY, _("name")); + goto cleanup; + } + vol = vol->next; + i++; + } + + return i; + + cleanup: + for (i = 0 ; i < maxnames ; i++) { + free(names[i]); + names[i] = NULL; + } + memset(names, 0, maxnames); + return -1; +} + + +static virStorageVolPtr +storageVolumeLookupByName(virStoragePoolPtr obj, + const char *name) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStorageVolDefPtr vol; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return NULL; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("storage pool is not active")); + return NULL; + } + + vol = virStorageVolDefFindByName(pool, name); + + if (!vol) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage vol with matching name")); + return NULL; + } + + return virGetStorageVol(obj->conn, pool->def->name, vol->name, vol->key); +} + + +static virStorageVolPtr +storageVolumeLookupByKey(virConnectPtr conn, + const char *key) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)conn->storagePrivateData; + virStoragePoolObjPtr pool = driver->pools; + + while (pool) { + if (virStoragePoolObjIsActive(pool)) { + virStorageVolDefPtr vol = virStorageVolDefFindByKey(pool, key); + + if (vol) + return virGetStorageVol(conn, + pool->def->name, + vol->name, + vol->key); + } + pool = pool->next; + } + + virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL, + _("no storage vol with matching key")); + return NULL; +} + +static virStorageVolPtr +storageVolumeLookupByPath(virConnectPtr conn, + const char *path) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)conn->storagePrivateData; + virStoragePoolObjPtr pool = driver->pools; + + while (pool) { + if (virStoragePoolObjIsActive(pool)) { + virStorageVolDefPtr vol = virStorageVolDefFindByPath(pool, path); + + if (vol) + return virGetStorageVol(conn, + pool->def->name, + vol->name, + vol->key); + } + pool = pool->next; + } + + virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL, + _("no storage vol with matching path")); + return NULL; +} + +static virStorageVolPtr +storageVolumeCreateXML(virStoragePoolPtr obj, + const char *xmldesc, + unsigned int flags ATTRIBUTE_UNUSED) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid); + virStorageBackendPtr backend; + virStorageVolDefPtr vol; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return NULL; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("storage pool is not active")); + return NULL; + } + + if ((backend = virStorageBackendForType(pool->def->type)) == NULL) + return NULL; + + vol = virStorageVolDefParse(obj->conn, pool->def, xmldesc, NULL); + if (vol == NULL) + return NULL; + + if (virStorageVolDefFindByName(pool, vol->name)) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("storage vol already exists")); + virStorageVolDefFree(vol); + return NULL; + } + + if (!backend->createVol) { + virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT, + _("storage pool does not support volume creation")); + virStorageVolDefFree(vol); + return NULL; + } + + if (backend->createVol(obj->conn, pool, vol) < 0) { + virStorageVolDefFree(vol); + return NULL; + } + + vol->next = pool->volumes; + pool->volumes = vol; + pool->nvolumes++; + + return virGetStorageVol(obj->conn, pool->def->name, vol->name, vol->key); +} + +static int +storageVolumeDelete(virStorageVolPtr obj, + unsigned int flags) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByName(driver, obj->pool); + virStorageBackendPtr backend; + virStorageVolDefPtr vol, tmp, prev; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return -1; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("storage pool is not active")); + return -1; + } + + if ((backend = virStorageBackendForType(pool->def->type)) == NULL) + return -1; + + vol = virStorageVolDefFindByName(pool, obj->name); + + if (!vol) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage vol with matching name")); + return -1; + } + + if (!backend->deleteVol) { + virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT, + _("storage pool does not support vol deletion")); + virStorageVolDefFree(vol); + return -1; + } + + if (backend->deleteVol(obj->conn, pool, vol, flags) < 0) { + return -1; + } + + prev = NULL; + tmp = pool->volumes; + while (tmp) { + if (tmp == vol) { + break; + } + prev = tmp; + tmp = tmp->next; + } + if (prev) { + prev->next = vol->next; + } else { + pool->volumes = vol->next; + } + pool->nvolumes--; + virStorageVolDefFree(vol); + + return 0; +} + +static int +storageVolumeGetInfo(virStorageVolPtr obj, + virStorageVolInfoPtr info) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByName(driver, obj->pool); + virStorageBackendPtr backend; + virStorageVolDefPtr vol; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return -1; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("storage pool is not active")); + return -1; + } + + vol = virStorageVolDefFindByName(pool, obj->name); + + if (!vol) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage vol with matching name")); + return -1; + } + + if ((backend = virStorageBackendForType(pool->def->type)) == NULL) + return -1; + + if (backend->refreshVol && + backend->refreshVol(obj->conn, pool, vol) < 0) + return -1; + + memset(info, 0, sizeof(*info)); + info->type = backend->volType; + info->capacity = vol->capacity; + info->allocation = vol->allocation; + + return 0; +} + +static char * +storageVolumeGetXMLDesc(virStorageVolPtr obj, + unsigned int flags ATTRIBUTE_UNUSED) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByName(driver, obj->pool); + virStorageBackendPtr backend; + virStorageVolDefPtr vol; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return NULL; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("storage pool is not active")); + return NULL; + } + + vol = virStorageVolDefFindByName(pool, obj->name); + + if (!vol) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage vol with matching name")); + return NULL; + } + + if ((backend = virStorageBackendForType(pool->def->type)) == NULL) + return NULL; + + return virStorageVolDefFormat(obj->conn, pool->def, vol); +} + +static char * +storageVolumeGetPath(virStorageVolPtr obj) { + virStorageDriverStatePtr driver = + (virStorageDriverStatePtr)obj->conn->storagePrivateData; + virStoragePoolObjPtr pool = virStoragePoolObjFindByName(driver, obj->pool); + virStorageVolDefPtr vol; + char *ret; + + if (!pool) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage pool with matching uuid")); + return NULL; + } + + if (!virStoragePoolObjIsActive(pool)) { + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, + _("storage pool is not active")); + return NULL; + } + + vol = virStorageVolDefFindByName(pool, obj->name); + + if (!vol) { + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, + _("no storage vol with matching name")); + return NULL; + } + + ret = strdup(vol->target.path); + if (ret == NULL) { + virStorageReportError(obj->conn, VIR_ERR_NO_MEMORY, _("path")); + return NULL; + } + return ret; +} + + + + + +static virStorageDriver storageDriver = { + "storage", + storageOpen, + storageClose, + storageNumPools, + storageListPools, + storageNumDefinedPools, + storageListDefinedPools, + storagePoolLookupByName, + storagePoolLookupByUUID, + storagePoolLookupByVolume, + storagePoolCreate, + storagePoolDefine, + storagePoolBuild, + storagePoolUndefine, + storagePoolStart, + storagePoolDestroy, + storagePoolDelete, + storagePoolRefresh, + storagePoolGetInfo, + storagePoolDumpXML, + storagePoolGetAutostart, + storagePoolSetAutostart, + storagePoolNumVolumes, + storagePoolListVolumes, + storageVolumeLookupByName, + storageVolumeLookupByKey, + storageVolumeLookupByPath, + storageVolumeCreateXML, + storageVolumeDelete, + storageVolumeGetInfo, + storageVolumeGetXMLDesc, + storageVolumeGetPath +}; + + +static virStateDriver stateDriver = { + storageDriverStartup, + storageDriverShutdown, + storageDriverReload, + storageDriverActive, +}; + +int storageRegister(void) { + virRegisterStorageDriver(&storageDriver); + virRegisterStateDriver(&stateDriver); + return 0; +} + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r d043e3715bce src/storage_driver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/storage_driver.h Tue Feb 19 16:59:10 2008 -0500 @@ -0,0 +1,45 @@ +/* + * storage_driver.h: core driver for storage APIs + * + * Copyright (C) 2006-2008 Red Hat, Inc. + * Copyright (C) 2006-2008 Daniel P. Berrange + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> + */ + +#ifndef __VIR_STORAGE_DRIVER_H__ +#define __VIR_STORAGE_DRIVER_H__ + +#include "storage_conf.h" + +int storageRegister(void); + +#endif /* __VIR_STORAGE_DRIVER_H__ */ + +/* + * vim: set tabstop=4: + * vim: set shiftwidth=4: + * vim: set expandtab: + */ +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r d043e3715bce src/virterror.c --- a/src/virterror.c Tue Feb 19 16:26:35 2008 -0500 +++ b/src/virterror.c Tue Feb 19 16:59:10 2008 -0500 @@ -678,6 +678,18 @@ __virErrorMsg(virErrorNumber error, cons else errmsg = _("authentication failed: %s"); break; + case VIR_ERR_NO_STORAGE_POOL: + if (info == NULL) + errmsg = _("Storage pool not found"); + else + errmsg = _("Storage pool not found: %s"); + break; + case VIR_ERR_NO_STORAGE_VOL: + if (info == NULL) + errmsg = _("Storage volume not found"); + else + errmsg = _("Storage volume not found: %s"); + break; case VIR_ERR_INVALID_STORAGE_POOL: if (info == NULL) errmsg = _("invalid storage pool pointer in"); -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list