--- /dev/null
+#
+# TODO:
+# - seems that lxc patch is not needed anymore, verify that before removing
+# - pldize virtlockd.init
+#
+# Conditional build:
+%bcond_without ceph # RADOS BD (Ceph) storage support
+%bcond_without esx # VMware ESX support
+%bcond_without glusterfs # GlusterFS storage support
+%bcond_without hyperv # Hyper-V support
+%bcond_without libxl # libxenlight support
+%bcond_without lxc # LXC support
+%bcond_without netcf # host interfaces support
+%bcond_without openvz # OpenVZ support
+%bcond_without phyp # PHYP support
+%bcond_without polkit # PolicyKit support
+%bcond_without qemu # Qemu support
+%bcond_without sanlock # sanlock storage lock manager
+%bcond_without systemtap # systemtap/dtrace probes
+%bcond_without uml # UML support
+%bcond_without vbox # VirtualBox support
+%bcond_without vmware # VMware Workstation/Player support
+%bcond_with vserver # Support for Linux-VServer guests
+%bcond_without xenapi # Xen API (Citrix XenServer) support
+%bcond_without xen # Xen support
+%bcond_without static_libs # static libraries build
+
+# qemu available only on x86 and ppc
+%ifnarch %{ix86} %{x8664} ppc
+%undefine with_qemu
+%endif
+# Xen is available only on x86 and ia64
+%ifnarch %{ix86} %{x8664} ia64
+%undefine with_xen
+%endif
+
+Summary: Toolkit to interact with virtualization capabilities
+Summary(pl.UTF-8): Narzędzia współpracujące z funkcjami wirtualizacji
+Name: libvirt
+Version: 1.2.8
+Release: 1
+License: LGPL v2.1+
+Group: Libraries
+Source0: ftp://ftp.libvirt.org/libvirt/%{name}-%{version}.tar.gz
+# Source0-md5: 75114991290f7c8f01dd5223431b9c00
+Source1: %{name}.init
+Source2: %{name}.tmpfiles
+Patch0: %{name}-sasl.patch
+Patch1: %{name}-lxc.patch
+Patch2: %{name}-qemu-acl.patch
+Patch3: %{name}-xend.patch
+Patch4: virtlockd.init.patch
+Patch5: %{name}-udevadm-settle.patch
+Patch6: vserver.patch
+Patch7: bashisms.patch
+Patch8: libvirt-guests.init.patch
+URL: http://www.libvirt.org/
+BuildRequires: audit-libs-devel
+BuildRequires: augeas-devel
+BuildRequires: autoconf >= 2.50
+BuildRequires: automake
+BuildRequires: avahi-devel >= 0.6.0
+%{?with_ceph:BuildRequires: ceph-devel}
+BuildRequires: curl-devel >= 7.18.0
+BuildRequires: cyrus-sasl-devel
+BuildRequires: dbus-devel >= 1.0.0
+BuildRequires: device-mapper-devel >= 1.0.0
+BuildRequires: gawk
+BuildRequires: gettext-devel >= 0.17
+%{?with_glusterfs:BuildRequires: glusterfs-devel >= 3.4.1}
+BuildRequires: gnutls-devel >= 1.0.25
+BuildRequires: libapparmor-devel
+BuildRequires: libblkid-devel >= 2.17
+BuildRequires: libcap-ng-devel >= 0.4.0
+BuildRequires: libfuse-devel >= 2.8.6
+BuildRequires: libgcrypt-devel
+BuildRequires: libnl-devel >= 3.2
+BuildRequires: libpcap-devel >= 1.0.0
+BuildRequires: libselinux-devel >= 2.0.82
+BuildRequires: libssh2-devel >= 1.3
+BuildRequires: libtool
+%{?with_xenapi:BuildRequires: libxenserver-devel}
+BuildRequires: libxml2-devel >= 1:2.6.0
+BuildRequires: libxslt-devel
+BuildRequires: ncurses-devel
+%{?with_netcf:BuildRequires: netcf-devel >= 0.2.0}
+BuildRequires: numactl-devel
+BuildRequires: openldap-devel
+BuildRequires: openwsman-devel >= 2.2.3
+BuildRequires: parted-devel >= 1.8.0
+BuildRequires: pkgconfig
+BuildRequires: polkit
+%{?with_polkit:BuildRequires: polkit-devel >= 0.90}
+BuildRequires: readline-devel
+BuildRequires: rpmbuild(macros) >= 1.627
+%{?with_sanlock:BuildRequires: sanlock-devel >= 0.8}
+BuildRequires: systemd-devel
+%{?with_systemtap:BuildRequires: systemtap-sdt-devel}
+BuildRequires: udev-devel >= 1:145
+%{?with_xen:BuildRequires: xen-devel >= 4.2}
+# For disk driver
+BuildRequires: xorg-lib-libpciaccess-devel >= 0.10.0
+BuildRequires: yajl-devel
+Requires: curl-libs >= 7.18.0
+Requires: device-mapper >= 1.0.0
+Requires: libcap-ng >= 0.4.0
+Requires: libnl >= 3.2
+Requires: libpcap >= 1.0.0
+Requires: libselinux >= 2.0.82
+Requires: libssh2 >= 1.3
+Requires: libxml2 >= 1:2.6.0
+Requires: openwsman-libs >= 2.2.3
+Obsoletes: libvirt-daemon-esx
+Obsoletes: libvirt-daemon-hyperv
+Obsoletes: libvirt-daemon-openvz
+Obsoletes: libvirt-daemon-phyp
+Obsoletes: libvirt-daemon-vbox
+Obsoletes: libvirt-daemon-vmware
+BuildRoot: %{tmpdir}/%{name}-%{version}-root-%(id -u -n)
+
+%description
+Libvirt is a C toolkit to interact with the virtualization
+capabilities of recent versions of Linux.
+
+Virtualization of the Linux Operating System means the ability to run
+multiple instances of Operating Systems concurently on a single
+hardware system where the basic resources are driven by a Linux
+instance. The library aim at providing long term stable C API
+initially for the Xen paravirtualization but should be able to
+integrate other virtualization mechanisms if needed.
+
+This package contains the base libraries and configuration file.
+
+%description -l pl.UTF-8
+Libvirt to zestaw narzędzi w C do współpracy z funkcjami wirtualizacji
+obecnych wersji Linuksa.
+
+Wirtualizacja w systemie operacyjnym Linux oznacza możliwość
+jednoczesnego uruchamiania wielu instancji systemu operacyjnego na
+pojedynczym systemie sprzętowym, którego podstawowe zasoby są
+zarzÄ…dzane przez instancjÄ™ Linuksa. Celem biblioteki jest zapewnienie
+długotrwale stabilnego API C, początkowo do parawirtualizacji Xen, ale
+dającej się zintegrować w razie potrzeby z innymi mechanizmami
+wirtualizacji.
+
+Ten pakiet zawiera podstawowe biblioteki oraz plik konfiguracyjny.
+
+%package devel
+Summary: Development files for programs using libvirt
+Summary(pl.UTF-8): Pliki programistyczne do programów wykorzystujących libvirt
+Group: Development/Libraries
+Requires: %{name} = %{version}-%{release}
+Requires: audit-libs-devel
+Requires: curl-devel >= 7.18.0
+Requires: dbus-devel >= 1.0.0
+Requires: device-mapper-devel >= 1.0.0
+Requires: gnutls-devel >= 1.0.25
+Requires: libapparmor-devel
+Requires: libcap-ng-devel >= 0.4.0
+Requires: libgcrypt-devel
+Requires: libnl-devel >= 3.2
+Requires: libpcap-devel >= 1.0.0
+Requires: libselinux-devel >= 2.0.82
+Requires: libxml2-devel >= 1:2.6.0
+Requires: numactl-devel
+Requires: openwsman-devel >= 2.2.3
+%{?with_xen:Requires: xen-devel >= 4.2}
+Requires: yajl-devel
+
+%description devel
+Libvirt is a C toolkit to interact with the virtualization
+capabilities of recent versions of Linux.
+
+This package contains the header files needed for developing programs
+using the libvirt library.
+
+%description devel -l pl.UTF-8
+Libvirt to zestaw narzędzi w C do współpracy z funkcjami wirtualizacji
+obecnych wersji Linuksa.
+
+Ten pakiet zawiera pliki nagłówkowe potrzebne do tworzenia programów
+wykorzystujÄ…cych bibliotekÄ™ libvirt.
+
+%package static
+Summary: Development static libraries for programs using libvirt
+Summary(pl.UTF-8): Statyczne biblioteki programistyczne do programów wykorzystujących libvirt
+Group: Development/Libraries
+Requires: %{name}-devel = %{version}-%{release}
+
+%description static
+Libvirt is a C toolkit to interact with the virtualization
+capabilities of recent versions of Linux.
+
+This package contains the static libraries for developing programs
+using the libvirt library.
+
+%description static -l pl.UTF-8
+Libvirt to zestaw narzędzi w C do współpracy z funkcjami wirtualizacji
+obecnych wersji Linuksa.
+
+Ten pakiet zawiera biblioteki statyczne do tworzenia programów
+wykorzystujÄ…cych bibliotekÄ™ libvirt.
+
+%package lock-sanlock
+Summary: Sanlock lock manager plugin for libvirt
+Summary(pl.UTF-8): ZarzÄ…dca blokad sanlock dla biblioteki libvirt
+Group: Libraries
+Requires: %{name}-daemon = %{version}-%{release}
+
+%description lock-sanlock
+Sanlock lock manager plugin for libvirt.
+
+%description lock-sanlock -l pl.UTF-8
+ZarzÄ…dca blokad sanlock dla biblioteki libvirt.
+
+%package daemon
+Summary: Server side daemon and supporting files for libvirt library
+Summary(pl.UTF-8): Demon działający po stronie serwera oraz pliki wspierające dla biblioteki libvirt
+Group: Applications/System
+Requires: %{name} = %{version}-%{release}
+Requires: avahi-libs >= 0.6.0
+Requires: iproute2
+Requires: libblkid >= 2.17
+%{?with_netcf:Requires: netcf >= 0.2.0}
+Requires: parted-libs >= 1.8.0
+Requires: rc-scripts
+# Needed for probing the power management features of the host.
+Requires: pm-utils
+Requires: systemd-units >= 37-0.10
+Requires: udev-libs >= 1:145
+Requires: util-linux
+Requires: virtual(module-tools)
+Requires: xorg-lib-libpciaccess >= 0.10.0
+Requires(post): systemd-units
+Requires(post,preun): /sbin/chkconfig
+Requires(postun): systemd-units
+Requires(preun): systemd-units
+Suggests: bridge-utils
+Suggests: cyrus-sasl
+Suggests: cyrus-sasl-digest-md5
+Suggests: dmidecode
+Suggests: dnsmasq >= 2.41
+Suggests: ebtables
+Suggests: gawk
+Suggests: glusterfs-client >= 2.0.1
+Suggests: iptables
+Suggests: iptables
+Suggests: libcgroup
+Suggests: lvm2
+Suggests: numad
+Suggests: open-iscsi
+Suggests: parted >= 1.8.0
+Suggests: polkit >= 0.93
+#Suggests: radvd
+Suggests: scrub
+#Suggests: sheepdog
+Provides: libvirt(hypervisor)
+
+%description daemon
+Server side daemon required to manage the virtualization capabilities
+of recent versions of Linux. Requires a hypervisor specific sub-RPM
+for specific drivers.
+
+%description daemon -l pl.UTF-8
+Demon działający po stronie serwera wymagany do zarządzania funkcjami
+wirtualizacji nowych wersji Linuksa. Wymaga podpakietu specyficznego
+dla hipernadzorcy.
+
+%package daemon-libxl
+Summary: Server side driver required to run XEN guests (xenlight)
+Summary(pl.UTF-8): Sterownik wymagany po stronie serwera do uruchamiania gości XEN (xenlight)
+Group: Libraries
+Requires: %{name}-daemon = %{version}-%{release}
+Requires: /usr/sbin/qcow-create
+Requires: xen
+Provides: libvirt(hypervisor)
+
+%description daemon-libxl
+Server side driver required to manage the virtualization capabilities
+of XEN via xenlight interface.
+
+%description daemon-libxl -l pl.UTF-8
+Sterownik wymagany po stronie serwera do zarzÄ…dzania funkcjami
+wirtualizacji XEN poprzez interfejs xenlight.
+
+%package daemon-lxc
+Summary: Server side driver required to run LXC guests
+Summary(pl.UTF-8): Sterownik wymagany po stronie serwera do uruchamiania gości LXC
+Group: Libraries
+Requires: %{name}-daemon = %{version}-%{release}
+Requires: libfuse >= 2.8.6
+Provides: libvirt(hypervisor)
+
+%description daemon-lxc
+Server side driver required to manage the virtualization capabilities
+of LXC.
+
+%description daemon-lxc -l pl.UTF-8
+Sterownik wymagany po stronie serwera do zarzÄ…dzania funkcjami
+wirtualizacji LXC.
+
+%package daemon-qemu
+Summary: Server side driver required to run QEMU guests
+Summary(pl.UTF-8): Sterownik wymagany po stronie serwera do uruchamiania gości QEMU
+Group: Libraries
+Requires: %{name}-daemon = %{version}-%{release}
+Requires: /usr/bin/qemu-img
+Requires: bzip2
+Requires: gzip
+Requires: lzop
+Requires: qemu
+Requires: xz
+Provides: libvirt(hypervisor)
+
+%description daemon-qemu
+Server side driver required to manage the virtualization capabilities
+of the QEMU emulators.
+
+%description daemon-qemu -l pl.UTF-8
+Sterownik wymagany po stronie serwera do zarzÄ…dzania funkcjami
+wirtualizacji emulatora QEMU.
+
+%package daemon-uml
+Summary: Server side driver required to run UML guests
+Summary(pl.UTF-8): Sterownik wymagany po stronie serwera do uruchamiania gości UML
+Group: Libraries
+Requires: %{name}-daemon = %{version}-%{release}
+Provides: libvirt(hypervisor)
+
+%description daemon-uml
+Server side driver required to manage the virtualization capabilities
+of UML.
+
+%description daemon-uml -l pl.UTF-8
+Sterownik wymagany po stronie serwera do zarzÄ…dzania funkcjami
+wirtualizacji UML.
+
+%package daemon-xen
+Summary: Server side driver required to run XEN guests
+Summary(pl.UTF-8): Sterownik wymagany po stronie serwera do uruchamiania gości XEN
+Group: Libraries
+Requires: %{name}-daemon = %{version}-%{release}
+Requires: /usr/sbin/qcow-create
+Requires: xen
+Requires: xen-xend
+Provides: libvirt(hypervisor)
+
+%description daemon-xen
+Server side driver required to manage the virtualization capabilities
+of XEN.
+
+%description daemon-xen -l pl.UTF-8
+Sterownik wymagany po stronie serwera do zarzÄ…dzania funkcjami
+wirtualizacji XEN.
+
+%package client
+Summary: Client side utilities of the libvirt library
+Summary(pl.UTF-8): Narzędzia klienckie do biblioteki libvirt
+Group: Applications/System
+Requires: %{name} = %{version}-%{release}
+Requires: gettext >= 0.18.1.1-6
+Requires: gnutls >= 1.0.25
+Requires: netcat-openbsd
+Requires: rc-scripts
+Requires(post): systemd-units
+Requires(post,preun): /sbin/chkconfig
+Requires(postun): systemd-units
+Requires(preun): systemd-units
+
+%description client
+Client binaries needed to access to the virtualization capabilities of
+recent versions of Linux (and other OSes).
+
+%description client -l pl.UTF-8
+Programy klienckie potrzebne do funkcji wirtualizacji nowych wersji
+Linuksa (oraz innych systemów operacyjnych).
+
+%package utils
+Summary: Tools to interact with virtualization capabilities (metapackage)
+Summary(pl.UTF-8): Narzędzia do współpracy z funkcjami wirtualizacyjnymi (metapakiet)
+Group: Applications/System
+Requires: %{name}-client = %{version}-%{release}
+Requires: %{name}-daemon = %{version}-%{release}
+%{?with_libxl:Requires: %{name}-daemon-libxl = %{version}-%{release}}
+Requires: %{name}-daemon-lxc = %{version}-%{release}
+Requires: %{name}-daemon-qemu = %{version}-%{release}
+Requires: %{name}-daemon-uml = %{version}-%{release}
+Requires: %{name}-daemon-xen = %{version}-%{release}
+
+%description utils
+Libvirt is a C toolkit to interact with the virtualization
+capabilities of recent versions of Linux.
+
+This is metapackage gathering all tools for the libvirt library.
+
+%description utils -l pl.UTF-8
+Libvirt to zestaw narzędzi w C do współpracy z funkcjami wirtualizacji
+obecnych wersji Linuksa.
+
+To jest metapakiet zbierający wszystkie narzędzia przeznaczone dla
+biblioteki libvirt.
+
+%package -n systemtap-libvirt
+Summary: systemtap/dtrace probes for libvirt
+Summary(pl.UTF-8): Sondy systemtap/dtrace dla libvirt
+Group: Development/Tools
+Requires: %{name} = %{version}-%{release}
+Requires: systemtap-client
+
+%description -n systemtap-libvirt
+systemtap/dtrace probes for libvirt.
+
+%description -n systemtap-libvirt -l pl.UTF-8
+Sondy systemtap/dtrace dla libvirt.
+
+%prep
+%setup -q
+%patch0 -p1
+# TODO
+#patch1 -p1
+%patch2 -p1
+%patch3 -p1
+%patch4 -p1
+%patch5 -p1
+%{?with_vserver:%patch6 -p1}
+%patch7 -p1
+%patch8 -p1
+
+%build
+%{__libtoolize}
+%{__aclocal} -I m4
+%{__autoconf}
+%{__autoheader}
+%{__automake}
+
+%configure \
+ PVCREATE=/sbin/pvcreate \
+ VGCREATE=/sbin/vgcreate \
+ LVCREATE=/sbin/lvcreate \
+ PVREMOVE=/sbin/pvremove \
+ VGREMOVE=/sbin/vgremove \
+ LVREMOVE=/sbin/lvremove \
+ VGCHANGE=/sbin/vgchange \
+ LVCHANGE=/sbin/lvchange \
+ VGSCAN=/sbin/vgscan \
+ PVS=/sbin/pvs \
+ VGS=/sbin/vgs \
+ LVS=/sbin/lvs \
+ TC=/sbin/tc \
+ BRCTL=/sbin/brctl \
+ ISCSIADM=/sbin/iscsiadm \
+ SHOWMOUNT=/usr/sbin/showmount \
+ MOUNT=/bin/mount \
+ UMOUNT=/bin/umount \
+ MKFS=/sbin/mkfs \
+ SHOWMOUNT=/usr/sbin/showmount \
+ IPTABLES_PATH=/usr/sbin/iptables \
+ IP6TABLES_PATH=/usr/sbin/ip6tables \
+ EBTABLES_PATH=/usr/sbin/ebtables \
+ ISCSIADM=/sbin/iscsiadm \
+ DNSMASQ=/usr/sbin/dnsmasq \
+ RADVD=/usr/sbin/radvd \
+ UDEVADM=/sbin/udevadm \
+ MODPROBE=/sbin/modprobe \
+ SCRUB=/usr/bin/scrub \
+ OVSVSCTL=/usr/bin/ovs-vsctl \
+ NUMAD=/usr/bin/numad \
+ COLLIE=/usr/sbin/collie \
+ --disable-silent-rules \
+ %{?with_static_libs:--enable-static} \
+ --with-html-dir=%{_gtkdocdir} \
+ --with-html-subdir=%{name} \
+ --with-init-script=systemd+redhat \
+ --with-packager="PLD-Linux" \
+ --with-packager-version="%{name}-%{version}-%{release}.%{_target_cpu}" \
+ --with-qemu-user=qemu \
+ --with-qemu-group=qemu \
+ --with-storage-disk \
+ --with-storage-fs \
+ --with-storage-gluster%{!?with_glusterfs:=no} \
+ --with-storage-iscsi \
+ --with-storage-lvm \
+ --with-storage-mpath \
+ --with-storage-rbd%{!?with_ceph:=no} \
+ --with-storage-scsi \
+ --with-storage-sheepdog \
+ --with-apparmor \
+ --with-audit \
+ --with-avahi \
+ %{__with_without systemtap dtrace} \
+ %{__with_without esx} \
+ --with-driver-modules \
+ --without-hal \
+ %{__with_without hyperv} \
+ --with-blkid \
+ --with-ssh2 \
+ %{__with_without libxl} \
+ %{__with_without lxc} \
+ --with-macvtap \
+ %{__with_without netcf} \
+ --with-numactl \
+ --with-numad \
+ %{__with_without openvz} \
+ %{__with_without phyp} \
+ %{__with_without polkit} \
+ %{__with_without qemu} \
+ %{__with_without sanlock} \
+ --with-sasl \
+ --with-selinux \
+ --with-udev \
+ %{__with_without uml} \
+ %{__with_without vbox vbox %{_libdir}/VirtualBox} \
+ --with-virtualport \
+ %{__with_without vmware} \
+ %{__with_without xen} \
+ %{__with_without xenapi} \
+ --with-yajl \
+ --x-libraries=%{_libdir}
+
+%{__make} \
+ AWK=gawk
+
+%install
+rm -rf $RPM_BUILD_ROOT
+install -d $RPM_BUILD_ROOT/etc/{sysconfig,rc.d/init.d} \
+ $RPM_BUILD_ROOT%{systemdtmpfilesdir}
+
+%{__make} install \
+ DEVHELP_DIR=%{_gtkdocdir}/%{name}/devhelp \
+ SYSTEMD_UNIT_DIR=%{systemdunitdir} \
+ DESTDIR=$RPM_BUILD_ROOT
+
+install %{SOURCE1} $RPM_BUILD_ROOT/etc/rc.d/init.d/libvirtd
+install %{SOURCE2} $RPM_BUILD_ROOT%{systemdtmpfilesdir}/%{name}.conf
+
+%{__rm} $RPM_BUILD_ROOT%{_libdir}/*.la
+%{__rm} $RPM_BUILD_ROOT%{_libdir}/libvirt/connection-driver/*.la \
+ %{?with_static_libs:$RPM_BUILD_ROOT%{_libdir}/libvirt/connection-driver/*.a}
+
+%if %{with sanlock}
+%{__rm} $RPM_BUILD_ROOT%{_libdir}/libvirt/lock-driver/*.la \
+ %{?with_static_libs:$RPM_BUILD_ROOT%{_libdir}/libvirt/lock-driver/*.a}
+%endif
+
+%{__mv} $RPM_BUILD_ROOT%{_localedir}/{eu_ES,eu}
+# duplicate of vi, just one less message translated
+%{__rm} -r $RPM_BUILD_ROOT%{_localedir}/vi_VN
+
+%find_lang %{name}
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post -p /sbin/ldconfig
+%postun -p /sbin/ldconfig
+
+%post daemon
+/sbin/chkconfig --add libvirtd
+%service libvirtd restart
+%systemd_post libvirtd.service
+
+%preun daemon
+if [ "$1" = "0" ]; then
+ %service -q libvirtd stop
+ /sbin/chkconfig --del libvirtd
+fi
+%systemd_preun libvirtd.service
+
+%postun daemon
+%systemd_reload
+
+%post client
+/sbin/chkconfig --add libvirt-guests
+%service -n libvirt-guests restart
+NORESTART=1
+%systemd_post libvirt-guests.service
+
+%preun client
+%systemd_preun libvirt-guests.service
+if [ "$1" = "0" ]; then
+ %service -q libvirt-guests stop
+ /sbin/chkconfig --del libvirt-guests
+fi
+
+%postun client
+%systemd_reload
+
+%files -f %{name}.lang
+%defattr(644,root,root,755)
+%doc ChangeLog README TODO NEWS
+%dir %{_sysconfdir}/libvirt
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/libvirt.conf
+%attr(755,root,root) %{_libdir}/libvirt.so.*.*.*
+%attr(755,root,root) %ghost %{_libdir}/libvirt.so.0
+%if %{with lxc}
+%attr(755,root,root) %{_libdir}/libvirt-lxc.so.*.*.*
+%attr(755,root,root) %ghost %{_libdir}/libvirt-lxc.so.0
+%endif
+%if %{with qemu}
+%attr(755,root,root) %{_libdir}/libvirt-qemu.so.*.*.*
+%attr(755,root,root) %ghost %{_libdir}/libvirt-qemu.so.0
+%endif
+
+%dir %{_libdir}/libvirt
+%dir %{_datadir}/libvirt
+%{_datadir}/libvirt/libvirtLogo.png
+
+%files devel
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_libdir}/libvirt.so
+%{?with_lxc:%attr(755,root,root) %{_libdir}/libvirt-lxc.so}
+%{?with_qemu:%attr(755,root,root) %{_libdir}/libvirt-qemu.so}
+%{_datadir}/%{name}/api
+%{_gtkdocdir}/%{name}
+%{_includedir}/%{name}
+%{_pkgconfigdir}/libvirt.pc
+%{?with_lxc:%{_pkgconfigdir}/libvirt-lxc.pc}
+%{?with_qemu:%{_pkgconfigdir}/libvirt-qemu.pc}
+
+%files static
+%defattr(644,root,root,755)
+%{_libdir}/libvirt.a
+%{?with_lxc:%{_libdir}/libvirt-lxc.a}
+%{?with_qemu:%{_libdir}/libvirt-qemu.a}
+
+%if %{with sanlock}
+%files lock-sanlock
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_sbindir}/virt-sanlock-cleanup
+%attr(755,root,root) %{_libdir}/libvirt_sanlock_helper
+%attr(755,root,root) %{_libdir}/libvirt/lock-driver/sanlock.so
+%{_datadir}/augeas/lenses/libvirt_sanlock.aug
+%{_datadir}/augeas/lenses/tests/test_libvirt_sanlock.aug
+%dir /var/lib/libvirt/sanlock
+%{_mandir}/man8/virt-sanlock-cleanup.8*
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/qemu-sanlock.conf
+%endif
+
+%files daemon
+%defattr(644,root,root,755)
+%doc docs/*.xml
+%dir %attr(700,root,root) %{_sysconfdir}/libvirt/nwfilter
+%dir %attr(700,root,root) %{_sysconfdir}/libvirt/qemu
+%dir %attr(700,root,root) %{_sysconfdir}/libvirt/qemu/networks
+%dir %attr(700,root,root) %{_sysconfdir}/libvirt/qemu/networks/autostart
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/libvirtd.conf
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/qemu-lockd.conf
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/virtlockd.conf
+%config(noreplace,missingok) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/qemu/networks/default.xml
+%config(noreplace,missingok) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/qemu/networks/autostart/default.xml
+%config(noreplace,missingok) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/nwfilter/*.xml
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/sasl/libvirt.conf
+%config(noreplace) %verify(not md5 mtime size) /etc/sysconfig/libvirtd
+%config(noreplace) %verify(not md5 mtime size) /etc/sysconfig/virtlockd
+%attr(754,root,root) /etc/rc.d/init.d/libvirtd
+%attr(754,root,root) /etc/rc.d/init.d/virtlockd
+%{systemdunitdir}/libvirtd.service
+%{systemdunitdir}/libvirtd.socket
+%{systemdunitdir}/virtlockd.service
+%{systemdunitdir}/virtlockd.socket
+%config(noreplace) %verify(not md5 mtime size) /usr/lib/sysctl.d/libvirtd.conf
+%config(noreplace) %verify(not md5 mtime size) /etc/logrotate.d/libvirtd
+%attr(755,root,root) %{_libdir}/libvirt_iohelper
+%attr(755,root,root) %{_libdir}/libvirt_parthelper
+%attr(755,root,root) %{_libdir}/virt-aa-helper
+%attr(755,root,root) %{_sbindir}/libvirtd
+%attr(755,root,root) %{_sbindir}/virtlockd
+%{_datadir}/augeas/lenses/libvirtd.aug
+%{_datadir}/augeas/lenses/libvirt_lockd.aug
+%{_datadir}/augeas/lenses/virtlockd.aug
+%{_datadir}/augeas/lenses/tests/test_libvirtd.aug
+%{_datadir}/augeas/lenses/tests/test_libvirt_lockd.aug
+%{_datadir}/augeas/lenses/tests/test_virtlockd.aug
+%if %{with polkit}
+%{_datadir}/polkit-1/actions/org.libvirt.api.policy
+%{_datadir}/polkit-1/actions/org.libvirt.unix.policy
+%endif
+%{_mandir}/man8/libvirtd.8*
+%{_mandir}/man8/virtlockd.8*
+%dir /var/lib/libvirt
+%dir /var/lib/libvirt/dnsmasq
+%attr(711,root,root) %dir /var/lib/libvirt/boot
+%attr(700,root,root) %dir /var/lib/libvirt/network
+%attr(711,root,root) %dir /var/lib/libvirt/images
+%attr(711,root,root) %dir /var/lib/libvirt/filesystems
+%attr(700,root,root) %dir /var/log/libvirt
+%attr(711,root,root) %dir /var/cache/libvirt
+%dir /var/run/libvirt
+%dir /var/run/libvirt/network
+%{systemdtmpfilesdir}/%{name}.conf
+%attr(755,root,root) %{_libexecdir}/libvirt_leaseshelper
+%dir %{_libdir}/libvirt/connection-driver
+%{_datadir}/libvirt/cpu_map.xml
+%{?with_netcf:%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_interface.so}
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_network.so
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_nodedev.so
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_nwfilter.so
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_secret.so
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_storage.so
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_vbox.so
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_vbox_network.so
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_vbox_storage.so
+%dir %{_libdir}/libvirt/lock-driver
+%attr(755,root,root) %{_libdir}/libvirt/lock-driver/lockd.so
+
+%if %{with libxl}
+%files daemon-libxl
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_libxl.so
+%attr(700,root,root) %dir /var/lib/libvirt/libxl
+%attr(700,root,root) %dir /var/run/libvirt/libxl
+%attr(700,root,root) %dir /var/log/libvirt/libxl
+%endif
+
+%if %{with lxc}
+%files daemon-lxc
+%defattr(644,root,root,755)
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/lxc.conf
+%config(noreplace) %verify(not md5 mtime size) /etc/logrotate.d/libvirtd.lxc
+%attr(700,root,root) %dir /var/lib/libvirt/lxc
+%attr(700,root,root) %dir /var/run/libvirt/lxc
+%attr(700,root,root) %dir /var/log/libvirt/lxc
+%{_datadir}/augeas/lenses/libvirtd_lxc.aug
+%{_datadir}/augeas/lenses/tests/test_libvirtd_lxc.aug
+%attr(755,root,root) %{_libdir}/libvirt_lxc
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_lxc.so
+%endif
+
+%if %{with qemu}
+%files daemon-qemu
+%defattr(644,root,root,755)
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/qemu.conf
+%config(noreplace) %verify(not md5 mtime size) /etc/logrotate.d/libvirtd.qemu
+%attr(750,qemu,qemu) %dir /var/cache/libvirt/qemu
+%attr(750,qemu,qemu) %dir /var/lib/libvirt/qemu
+%attr(700,root,root) %dir /var/log/libvirt/qemu
+%attr(700,root,root) %dir /var/run/libvirt/qemu
+%{_datadir}/augeas/lenses/libvirtd_qemu.aug
+%{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_qemu.so
+%endif
+
+%if %{with uml}
+%files daemon-uml
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_uml.so
+%config(noreplace) %verify(not md5 mtime size) /etc/logrotate.d/libvirtd.uml
+%attr(700,root,root) %dir /var/lib/libvirt/uml
+%attr(700,root,root) %dir /var/run/libvirt/uml
+%attr(700,root,root) %dir /var/log/libvirt/uml
+%endif
+
+%if %{with xen}
+%files daemon-xen
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_xen.so
+%endif
+
+%files client
+%defattr(644,root,root,755)
+%config(noreplace) %verify(not md5 mtime size) /etc/sysconfig/libvirt-guests
+%attr(754,root,root) /etc/rc.d/init.d/libvirt-guests
+%{systemdunitdir}/libvirt-guests.service
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/virt-login-shell.conf
+%attr(755,root,root) %{_bindir}/virsh
+%attr(755,root,root) %{_bindir}/virt-host-validate
+%attr(4755,root,root) %{_bindir}/virt-login-shell
+%attr(755,root,root) %{_bindir}/virt-xml-validate
+%attr(755,root,root) %{_bindir}/virt-pki-validate
+%attr(754,root,root) %{_libexecdir}/libvirt-guests.sh
+%{_mandir}/man1/virsh.1*
+%{_mandir}/man1/virt-host-validate.1*
+%{_mandir}/man1/virt-login-shell.1*
+%{_mandir}/man1/virt-xml-validate.1*
+%{_mandir}/man1/virt-pki-validate.1*
+%dir %{_datadir}/libvirt/schemas
+%{_datadir}/libvirt/schemas/basictypes.rng
+%{_datadir}/libvirt/schemas/capability.rng
+%{_datadir}/libvirt/schemas/domain.rng
+%{_datadir}/libvirt/schemas/domaincaps.rng
+%{_datadir}/libvirt/schemas/domaincommon.rng
+%{_datadir}/libvirt/schemas/domainsnapshot.rng
+%{_datadir}/libvirt/schemas/interface.rng
+%{_datadir}/libvirt/schemas/network.rng
+%{_datadir}/libvirt/schemas/networkcommon.rng
+%{_datadir}/libvirt/schemas/nodedev.rng
+%{_datadir}/libvirt/schemas/nwfilter.rng
+%{_datadir}/libvirt/schemas/secret.rng
+%{_datadir}/libvirt/schemas/storagecommon.rng
+%{_datadir}/libvirt/schemas/storagepool.rng
+%{_datadir}/libvirt/schemas/storagevol.rng
+
+%files utils
+%defattr(644,root,root,755)
+
+%if %{with systemtap}
+%files -n systemtap-libvirt
+%defattr(644,root,root,755)
+%{_datadir}/systemtap/tapset/libvirt_functions.stp
+%{_datadir}/systemtap/tapset/libvirt_probes.stp
+%{_datadir}/systemtap/tapset/libvirt_qemu_probes.stp
+%endif
--- /dev/null
+https://www.redhat.com/archives/libvir-list/2008-January/msg00097.html
+
+From: "Daniel Hokka Zakrisson" <daniel hozac com>
+To: libvir-list redhat com
+Subject: [Libvir] [PATCH] Linux-VServer support
+Date: Wed, 9 Jan 2008 22:51:20 +0100 (CET)
+
+This patch implements support for Linux-VServer guests. It is currently
+missing vcpu and console support, and the necessary virsh code to support
+it, but is otherwise pretty feature complete.
+
+This is an XML dump from one of my guests:
+<domain type='vserver' id='40010'>
+ <name>lenny</name>
+ <uuid>19e12957-261a-5a06-d6d0-89917d6d439f</uuid>
+ <memory>2048000</memory>
+ <os>
+ <hostname>lenny.test</hostname>
+ <type arch='i686'>vserver</type>
+ </os>
+ <devices>
+ <interface type='ethernet'>
+ <ip prefix='24' interface='dummy0' address='192.168.20.4' />
+ </interface>
+ <interface type='ethernet'>
+ <ip prefix='24' interface='dummy0' type='range' address='192.168.32.100' address2='192.168.32.200'/>
+ </interface>
+ <disk type='directory' device='directory'>
+ <source directory='/vservers/lenny' type='auto' options='defaults'/>
+ <target directory='/'/>
+ </disk>
+ <disk type='directory' device='directory'>
+ <source directory='/srv' type='ext3' options='bind,ro'/>
+ <target directory='/srv'/>
+ </disk>
+ <disk type='block' device='directory'>
+ <source dev='/dev/mapper/test' type='ext3' options='defaults'/>
+ <target directory='/mnt'/>
+ </disk>
+ </devices>
+</domain>
+
+--
+Daniel Hokka Zakrisson
+--- libvirt-1.2.3/configure.ac~ 2014-04-06 12:21:22.000000000 +0300
++++ libvirt-1.2.3/configure.ac 2014-04-06 12:22:55.249258975 +0300
+@@ -546,6 +546,10 @@
+ [AS_HELP_STRING([--with-parallels],
+ [add Parallels Cloud Server support @<:@default=check@:>@])])
+ m4_divert_text([DEFAULTS], [with_parallels=check])
++AC_ARG_WITH([vserver],
++ [AS_HELP_STRING([--with-vserver],
++ [add Linux-VServer support @<:@default=check@:>@])])
++m4_divert_text([DEFAULTS], [with_vserver=check])
+ AC_ARG_WITH([test],
+ [AS_HELP_STRING([--with-test],
+ [add test driver support @<:@default=yes@:>@])])
+@@ -991,6 +991,39 @@
+ fi
+ fi
+
++if test "$with_vserver" = "yes" ; then
++ AC_CHECK_LIB(vserver, [vc_rlimit_stat],, [with_vserver=no])
++ AC_CHECK_TYPES([xid_t, nid_t, tag_t])
++ AC_CHECK_HEADER(vserver.h,, [with_vserver=no], [AC_INCLUDES_DEFAULT()
++#ifndef HAVE_XID_T
++typedef unsigned int xid_t;
++#endif
++#ifndef HAVE_NID_T
++typedef unsigned int nid_t;
++#endif
++#ifndef HAVE_TAG_T
++typedef unsigned int tag_t;
++#endif])
++
++ AC_MSG_CHECKING([for vserver configuration directory])
++ VSERVER_CONF_DIR=`env PATH="/sbin:/usr/sbin:/usr/local/sbin:$PATH" \
++ vserver-info - SYSINFO | sed -n 's/^.*cfg-Directory:.//p'`
++ AC_MSG_RESULT([$VSERVER_CONF_DIR])
++ AC_DEFINE_UNQUOTED([VSERVER_CONF_DIR], ["$VSERVER_CONF_DIR"],
++ [The default path to the Linux-VServer configuration files])
++
++ AC_MSG_CHECKING([for the vserver program])
++ PROG_VSERVER=`env PATH="/sbin:/usr/sbin:/usr/local/sbin:$PATH" \
++ which vserver 2> /dev/null` || with_vserver=no
++ AC_MSG_RESULT([$PROG_VSERVER])
++ AC_DEFINE_UNQUOTED([PROG_VSERVER], ["$PROG_VSERVER"],
++ [The path to the vserver program])
++
++ if test "$with_vserver" = "yes" ; then
++ LIBVIRT_FEATURES="$LIBVIRT_FEATURES -DWITH_VSERVER"
++ fi
++fi
++
+
+ dnl
+ dnl check for kernel headers required by src/bridge.c
+@@ -2759,6 +2759,7 @@
+ AC_MSG_NOTICE([ ESX: $with_esx])
+ AC_MSG_NOTICE([ Hyper-V: $with_hyperv])
+ AC_MSG_NOTICE([Parallels: $with_parallels])
++AC_MSG_NOTICE([ VServer: $with_vserver])
+ LIBVIRT_DRIVER_RESULT_BHYVE
+ AC_MSG_NOTICE([ Test: $with_test])
+ AC_MSG_NOTICE([ Remote: $with_remote])
+--- libvirt-1.1.1/include/libvirt/virterror.h~ 2013-07-24 03:23:07.000000000 +0300
++++ libvirt-1.1.1/include/libvirt/virterror.h 2013-09-01 00:07:44.097192613 +0300
+@@ -121,6 +121,8 @@
+ VIR_FROM_ACCESS = 55, /* Error from access control manager */
+ VIR_FROM_SYSTEMD = 56, /* Error from systemd code */
+
++ VIR_FROM_VSERVER = 57, /* Error from Linux-VServer driver */
++
+ # ifdef VIR_ENUM_SENTINELS
+ VIR_ERR_DOMAIN_LAST
+ # endif
+--- libvirt-1.2.3/src/driver.h~ 2014-03-27 12:35:00.000000000 +0200
++++ libvirt-1.2.3/src/driver.h 2014-04-06 12:25:03.124800629 +0300
+@@ -48,6 +48,7 @@
+ VIR_DRV_HYPERV = 15,
+ VIR_DRV_PARALLELS = 16,
+ VIR_DRV_BHYVE = 17,
++ VIR_DRV_VSERVER = 18,
+ } virDrvNo;
+
+
+--- libvirt-1.1.1/src/libvirt.c~ 2013-09-01 00:20:50.000000000 +0300
++++ libvirt-1.1.1/src/libvirt.c 2013-09-01 00:21:02.812830784 +0300
+@@ -94,6 +94,9 @@
+ #ifdef WITH_PARALLELS
+ # include "parallels/parallels_driver.h"
+ #endif
++#ifdef WITH_VSERVER
++# include "server/vserver_driver.h"
++#endif
+
+ #define VIR_FROM_THIS VIR_FROM_NONE
+
+@@ -479,6 +482,10 @@
+ if (parallelsRegister() == -1)
+ goto error;
+ #endif
++#ifdef WITH_VSERVER
++ if (verversRegister() == -1)
++ goto error;
++#endif
+ #ifdef WITH_REMOTE
+ if (remoteRegister() == -1)
+ goto error;
+--- libvirt-1.1.1/src/Makefile.am~ 2013-07-30 10:21:31.000000000 +0300
++++ libvirt-1.1.1/src/Makefile.am 2013-09-01 00:11:19.080124997 +0300
+@@ -467,6 +467,7 @@
+ $(NWFILTER_DRIVER_SOURCES) \
+ $(OPENVZ_DRIVER_SOURCES) \
+ $(PARALLELS_DRIVER_SOURCES) \
++ $(VSERVER_DRIVER_SOURCES) \
+ $(PHYP_DRIVER_SOURCES) \
+ $(QEMU_DRIVER_SOURCES) \
+ $(REMOTE_DRIVER_SOURCES) \
+@@ -727,6 +728,12 @@
+ parallels/parallels_storage.c \
+ parallels/parallels_network.c
+
++VSERVER_DRIVER_SOURCES = \
++ vserver/vserver_driver.h \
++ vserver/vserver_driver.c \
++ vserver/vserver_conf.h \
++ vserver/vserver_conf.c
++
+ NETWORK_DRIVER_SOURCES = \
+ network/bridge_driver.h network/bridge_driver.c
+
+--- libvirt-1.2.3/src/util/virerror.c~ 2014-03-27 12:35:01.000000000 +0200
++++ libvirt-1.2.3/src/util/virerror.c 2014-04-06 12:25:58.523869047 +0300
+@@ -127,6 +127,7 @@
+
+ "Access Manager", /* 55 */
+ "Systemd",
++ "Vserver",
+ "Bhyve",
+ "Crypto",
+ )
+--- libvirt-0.4.0.orig/src/vserver/vserver_conf.c 1970-01-01 01:00:00.000000000 +0100
++++ libvirt-0.4.0.vserver/src/vserver/vserver_conf.c 2008-01-09 08:52:11.000000000 +0100
+@@ -0,0 +1,751 @@
++/*
++ * Configuration handling for Linux-VServer guests
++ *
++ * Copyright (C) 2007-2008 Daniel Hokka Zakrisson
++ *
++ * 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 Hokka Zakrisson <daniel hozac com>
++ */
++
++#ifdef WITH_VSERVER
++
++#define _GNU_SOURCE
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <fcntl.h>
++#include <dirent.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <arpa/inet.h>
++#include <net/if.h>
++#include <sys/stat.h>
++#include <ctype.h>
++
++#include <libvirt/virterror.h>
++
++#define IN_VSERVER 1
++#include "internal.h"
++#include "vserver_driver.h"
++#include "vserver_conf.h"
++#include "uuid.h"
++
++static int
++readStr(char *dst, size_t len, const char *name, const char *setting)
++{
++ char file[strlen(name) + strlen(setting) + 2];
++ int fd;
++ ssize_t bytes;
++ char *p;
++
++ sprintf(file, "%s/%s", name, setting);
++
++ /* a non-existant file is not a failure */
++ *dst = '\0';
++ if ((fd = open(file, O_RDONLY)) == -1)
++ return 1;
++
++ if ((bytes = read(fd, dst, len - 1)) == -1) {
++ close(fd);
++ return -1;
++ }
++ close(fd);
++
++ dst[bytes] = '\0';
++
++ if ((p = strchr(dst, '\n')) != NULL)
++ *p = '\0';
++
++ return 0;
++}
++
++static int
++readLong(void *v_dst, const char *name, const char *setting)
++{
++ char buf[128], *endptr;
++ int ret;
++ long *dst = v_dst;
++
++ ret = readStr(buf, sizeof(buf), name, setting);
++ if (ret)
++ return ret;
++
++ *dst = strtol(buf, &endptr, 0);
++ if (endptr && *endptr != '\0')
++ return -1;
++
++ return 0;
++}
++
++static int
++readInt(void *v_dst, const char *name, const char *setting)
++{
++ long val;
++ int *dst = v_dst;
++ int ret;
++
++ ret = readLong(&val, name, setting);
++ if (ret)
++ return ret;
++
++ *dst = (int) val;
++
++ return 0;
++}
++
++static int
++readBool(char *dst, const char *name, const char *setting)
++{
++ char file[strlen(name) + strlen(setting) + 2];
++
++ sprintf(file, "%s/%s", name, setting);
++
++ *dst = access(file, F_OK) != -1;
++
++ return 0;
++}
++
++int
++vserverWriteToConfig(struct vserver_guest *guest, const char *filename,
++ const char *format, ...)
++{
++ char path[strlen(guest->path) + 1 + strlen(filename) + 1];
++ va_list va;
++ char value[1024];
++ int fd;
++ ssize_t len, off, ret;
++ char *dir;
++
++ sprintf(path, "%s/%s", guest->path, filename);
++
++ /* ensure the directory exists */
++ dir = strrchr(path, '/');
++ *dir = '\0';
++ if (mkdir(path, 0755) && errno != EEXIST)
++ return -1;
++ *dir = '/';
++
++ va_start(va, format);
++ if (strcmp(format, "%b") == 0) {
++ /* bool, this is a special case */
++ if (va_arg(va, int)) {
++ *value = '\0';
++ len = 0;
++ }
++ else {
++ if (unlink(path) == -1 && errno != ENOENT)
++ return -1;
++ else
++ return 0;
++ }
++ }
++ else
++ len = vsnprintf(value, sizeof(value), format, va);
++ va_end(va);
++
++ fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, 0644);
++ if (fd == -1)
++ return -1;
++
++ for (off = 0; off < len; off += ret) {
++ ret = write(fd, value + off, len - off);
++ if (ret == -1) {
++ close(fd);
++ return -1;
++ }
++ }
++
++ if (close(fd) == -1)
++ return -1;
++ return 0;
++}
++
++#define WRITE(...) if (vserverWriteToConfig(guest, __VA_ARGS__) == -1) \
++ return -1
++#define WRITE_SCHED_VAL(sched, file, mask, format, value) \
++ if ((sched)->set_mask & mask) { \
++ WRITE(file, format, value); \
++ }
++#define WRITE_SCHED(dir, sched) \
++ do { \
++ WRITE_SCHED_VAL(sched, dir "/fill-rate", \
++ VC_VXSM_FILL_RATE, "%u\n", \
++ (sched)->fill_rate); \
++ WRITE_SCHED_VAL(sched, dir "/interval", \
++ VC_VXSM_INTERVAL, "%u\n", \
++ (sched)->interval); \
++ WRITE_SCHED_VAL(sched, dir "/fill-rate2", \
++ VC_VXSM_FILL_RATE2, "%u\n", \
++ (sched)->fill_rate2); \
++ WRITE_SCHED_VAL(sched, dir "/interval2", \
++ VC_VXSM_INTERVAL2, "%u\n", \
++ (sched)->interval2); \
++ WRITE_SCHED_VAL(sched, dir "/tokens-min", \
++ VC_VXSM_TOKENS_MIN, "%u\n", \
++ (sched)->tokens_min); \
++ WRITE_SCHED_VAL(sched, dir "/tokens-max", \
++ VC_VXSM_TOKENS_MAX, "%u\n", \
++ (sched)->tokens_max); \
++ WRITE_SCHED_VAL(sched, dir "/priority-bias", \
++ VC_VXSM_PRIO_BIAS, "%u\n", \
++ (sched)->priority_bias); \
++ WRITE(dir "/idle-time", "%b", \
++ (sched)->set_mask & VC_VXSM_IDLE_TIME); \
++ } while (0)
++#define WRITE_IP(filename, v4var, v6var) \
++ strcpy(file, filename); \
++ switch (type) { \
++ case VC_NXA_TYPE_IPV4: \
++ inet_ntop(AF_INET, (v4var), buf, sizeof(buf)); \
++ break; \
++ case VC_NXA_TYPE_IPV6: \
++ inet_ntop(AF_INET6, (v6var), buf, sizeof(buf)); \
++ break; \
++ } \
++ WRITE(dir, "%s\n", buf);
++
++static int
++writeInterfaces(struct vserver_guest *guest)
++{
++ char name[strlen(guest->path) + sizeof("/interfaces/XXXXXX/prefix")],
++ *dir, *file;
++ char buf[128];
++ struct vserver_ip *ip;
++ unsigned int i;
++
++ snprintf(name, sizeof(name), "%s/interfaces", guest->path);
++ if (vserverRunCommand(0, "rm", "-fr", name, NULL) != 0)
++ return -1;
++ if (mkdir(name, 0755) == -1)
++ return -1;
++
++ dir = name + strlen(guest->path) + 1;
++ for (ip = guest->ips, i = 0; ip; ip = ip->next, i++) {
++ uint16_t type;
++
++ /* Yeah right... */
++ if (i > 999999) {
++ errno = EOVERFLOW;
++ return -1;
++ }
++
++ file = dir;
++ file += snprintf(dir, sizeof(name) - (dir - name), "interfaces/%u", i);
++ if (mkdir(name, 0755) == -1)
++ return -1;
++
++ type = ip->addr.vna_type & (VC_NXA_TYPE_IPV4|VC_NXA_TYPE_IPV6);
++
++ strcpy(file, "/prefix");
++ WRITE(dir, "%u\n", ip->addr.vna_prefix);
++
++ if (*ip->interface) {
++ strcpy(file, "/dev");
++ WRITE(dir, "%s\n", ip->interface);
++ }
++ else {
++ strcpy(file, "/nodev");
++ WRITE(dir, "%b", 1);
++ }
++
++ WRITE_IP("/ip", &ip->addr.vna_v4_ip, &ip->addr.vna_v6_ip);
++ if (ip->addr.vna_type & VC_NXA_TYPE_RANGE) {
++ WRITE_IP("/ip2", &ip->addr.vna_v4_ip2, &ip->addr.vna_v6_ip2);
++ }
++ if (ip->addr.vna_type & (VC_NXA_TYPE_RANGE|VC_NXA_TYPE_MASK)) {
++ WRITE_IP("/mask", &ip->addr.vna_v4_mask, &ip->addr.vna_v6_mask);
++ }
++ }
++ return 0;
++}
++
++static int
++writeFstab(struct vserver_guest *guest)
++{
++ FILE *fp;
++ struct vserver_fstab *ent;
++ char file[strlen(guest->path) + sizeof("/fstab")];
++
++ sprintf(file, "%s/fstab", guest->path);
++ fp = fopen(file, "w");
++ if (fp == NULL)
++ return -1;
++
++ for (ent = guest->fstab; ent; ent = ent->next) {
++ if (!(ent->flags & VSERVER_FSTAB_OUTPUT))
++ continue;
++ fprintf(fp, "%s\t%s\t%s\t%s\t%s\n", ent->source, ent->target,
++ ent->fstype, ent->options, (ent->rest ? ent->rest : ""));
++ }
++
++ if (fclose(fp) == -1)
++ return -1;
++
++ return 0;
++}
++
++int
++vserverWriteGuestToConfig(struct vserver_guest *guest)
++{
++ char buf[128];
++
++ WRITE("context", "%u\n", guest->xid);
++ WRITE("name", "%s\n", guest->name);
++ virUUIDFormat(guest->uuid, buf);
++ WRITE("uuid", "%s\n", buf);
++ if (*guest->uts.hostname)
++ WRITE("uts/nodename", "%s\n", guest->uts.hostname);
++ if (*guest->uts.machine)
++ WRITE("uts/machine", "%s\n", guest->uts.machine);
++ if (*guest->uts.release)
++ WRITE("uts/release", "%s\n", guest->uts.release);
++ if (*guest->uts.version)
++ WRITE("uts/version", "%s\n", guest->uts.version);
++ if (guest->rss_hard > 0)
++ WRITE("rlimits/rss.hard", "%lu\n", guest->rss_hard);
++ WRITE("apps/init/mark", (guest->autostart ? "default\n" : "\n"));
++ WRITE_SCHED("sched", &guest->sched);
++
++ if (writeInterfaces(guest) == -1)
++ return -1;
++
++ if (writeFstab(guest) == -1)
++ return -1;
++
++ return 0;
++}
++#undef WRITE_IP
++#undef WRITE_SCHED
++#undef WRITE_SCHED_VAL
++#undef WRITE
++
++static int
++parseInterfaces(struct vserver_guest *guest, const char *directory)
++{
++ DIR *interfaces;
++ struct dirent *interface;
++ struct vserver_ip *ip = NULL;
++ char ipath[256], *subdir;
++ size_t spare;
++ char s_ip[48], s_prefix[4], s_mask[48], s_dev[32], s_ip2[48];
++
++ subdir = ipath;
++ subdir += snprintf(ipath, sizeof(ipath), "%s/%s", guest->name, directory);
++ spare = sizeof(ipath) - (subdir - ipath);
++
++ interfaces = opendir(ipath);
++ if (!interfaces)
++ return 0;
++
++ while ((interface = readdir(interfaces)) != NULL) {
++ if (*interface->d_name == '.')
++ continue;
++ /* would overflow */
++ if (strlen(interface->d_name) + sizeof("//disabled") > spare)
++ continue;
++
++ snprintf(subdir, spare, "/%s/disabled", interface->d_name);
++ if (access(ipath, F_OK) != -1)
++ continue;
++
++ snprintf(subdir, spare, "/%s", interface->d_name);
++ *s_mask = '\0';
++ *s_prefix = '\0';
++ if (readStr(s_ip, sizeof(s_ip), ipath, "ip") == 0 &&
++ (readStr(s_prefix, sizeof(s_prefix), ipath, "prefix") == 0 ||
++ readStr(s_mask, sizeof(s_mask), ipath, "mask") == 0)) {
++ if (readStr(s_dev, sizeof(s_dev), ipath, "dev") != 0)
++ *s_dev = '\0';
++ if (readStr(s_ip2, sizeof(s_ip2), ipath, "ip2") != 0)
++ *s_ip2 = '\0';
++ }
++ else
++ continue;
++
++ if (!ip)
++ guest->ips = ip = calloc(1, sizeof(*ip));
++ else {
++ ip->next = calloc(1, sizeof(*ip));
++ ip = ip->next;
++ }
++ if (!ip)
++ goto cleanup;
++
++ strcpy(ip->interface, s_dev);
++
++ if (inet_pton(AF_INET6, s_ip, &ip->addr.vna_v6_ip) > 0)
++ ip->addr.vna_type = VC_NXA_TYPE_IPV6;
++ else if (inet_pton(AF_INET, s_ip, &ip->addr.vna_v4_ip) > 0)
++ ip->addr.vna_type = VC_NXA_TYPE_IPV4;
++ else
++ goto cleanup;
++
++ if (ip->addr.vna_type == VC_NXA_TYPE_IPV6) {
++ if (*s_mask) {
++ if (inet_pton(AF_INET6, s_mask, &ip->addr.vna_v6_mask) <= 0)
++ goto cleanup;
++ }
++ if (*s_ip2) {
++ if (inet_pton(AF_INET6, s_ip2, &ip->addr.vna_v6_ip2) <= 0)
++ goto cleanup;
++ ip->addr.vna_type |= VC_NXA_TYPE_RANGE;
++ }
++ else
++ ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
++ }
++ else if (ip->addr.vna_type == VC_NXA_TYPE_IPV4) {
++ if (*s_mask) {
++ if (inet_pton(AF_INET, s_mask, &ip->addr.vna_v4_mask) <= 0)
++ goto cleanup;
++ }
++ if (*s_ip2) {
++ if (inet_pton(AF_INET, s_ip2, &ip->addr.vna_v4_ip2) <= 0)
++ goto cleanup;
++ ip->addr.vna_type |= VC_NXA_TYPE_RANGE;
++ }
++ else
++ ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
++ }
++
++ if (*s_prefix) {
++ char *endptr;
++ ip->addr.vna_prefix = strtoul(s_prefix, &endptr, 0);
++ if (*endptr != '\n' && *endptr)
++ goto cleanup;
++ }
++ }
++
++ closedir(interfaces);
++ return 0;
++
++cleanup:
++ closedir(interfaces);
++ return -1;
++}
++
++static inline char *
++endOfField(char *start)
++{
++ char *end;
++ for (end = start; *(end - 1) != '\\' &&
++ !isspace(*end) &&
++ *end != '\0'; end++)
++ ;
++ return end;
++}
++
++static inline char *
++startOfField(char *end)
++{
++ char *start;
++ for (start = end + 1; isspace(*start) &&
++ *start != '\0'; start++)
++ ;
++ return start;
++}
++
++static const struct {
++ int mode;
++ const char *type;
++} source_types[] = {
++ { S_IFBLK, "block" },
++ { S_IFREG, "file" },
++ { S_IFDIR, "directory" },
++};
++
++const char *
++vserverFindSourceType(const char *source)
++{
++ struct stat st;
++ int mode, i;
++ if (stat(source, &st) == -1)
++ mode = -1;
++ else
++ mode = st.st_mode & S_IFMT;
++ for (i = 0; i < (sizeof(source_types) / sizeof(*source_types)); i++) {
++ if (mode == source_types[i].mode)
++ return source_types[i].type;
++ }
++ return NULL;
++}
++
++static int
++parseFstab(struct vserver_guest *guest, const char *filename)
++{
++ FILE *fp;
++ char buf[256], *start, *end;
++ struct vserver_fstab *ent = NULL;
++ char path[strlen(guest->name) + 2 + strlen(filename)];
++
++ sprintf(path, "%s/%s", guest->name, filename);
++ if ((fp = fopen(path, "r")) == NULL)
++ return 0;
++
++ while (fgets(buf, sizeof(buf), fp) != NULL) {
++ if (!ent)
++ guest->fstab = ent = calloc(1, sizeof(*ent));
++ else {
++ ent->next = calloc(1, sizeof(*ent));
++ ent = ent->next;
++ }
++ if (!ent)
++ goto err;
++
++ start = buf;
++ end = endOfField(start);
++ *end = '\0';
++ ent->source = strdup(start);
++ ent->source_type = vserverFindSourceType(start);
++
++ ent->flags |= VSERVER_FSTAB_OUTPUT;
++ if (ent->source_type)
++ ent->flags |= VSERVER_FSTAB_SHOW;
++
++ start = startOfField(end);
++ end = endOfField(start);
++ *end = '\0';
++ ent->target = strdup(start);
++
++ start = startOfField(end);
++ end = endOfField(start);
++ *end = '\0';
++ ent->fstype = strdup(start);
++
++ start = startOfField(end);
++ end = endOfField(start);
++ if (*end != '\0') {
++ char *ptr;
++ ent->rest = strdup(end + 1);
++ ptr = strchr(ent->rest, '\n');
++ if (ptr)
++ *ptr = '\0';
++ }
++ else
++ ent->rest = NULL;
++ *end = '\0';
++ ent->options = strdup(start);
++
++ if (!ent->source || !ent->target || !ent->fstype || !ent->options)
++ goto err;
++ }
++
++ fclose(fp);
++ return 0;
++
++err:
++ fclose(fp);
++ return -1;
++}
++
++virDrvOpenStatus
++vserverInitializeDriver(virConnectPtr conn, struct vserver_driver *driver,
++ const char *path)
++{
++ struct vserver_guest *guest = NULL;
++ DIR *dp = NULL;
++ struct dirent *de;
++ int cwd;
++ const char *conf_dir = (*path ? path : VSERVER_CONF_DIR);
++
++ if (driver->initialized == 1)
++ return VIR_DRV_OPEN_SUCCESS;
++
++ driver->guests = NULL;
++ driver->inactive_guests = driver->active_guests = 0;
++
++ cwd = open(".", O_RDONLY);
++ if (cwd == -1 ||
++ chdir(conf_dir) == -1 ||
++ (dp = opendir(".")) == NULL) {
++ vserverError(conn, NULL, NULL, VIR_ERR_OPEN_FAILED, conf_dir);
++ goto error;
++ }
++
++ while ((de = readdir(dp)) != NULL) {
++ char uuidstr[VIR_UUID_STRING_BUFLEN + 1];
++ char mark[32];
++ char tmp;
++
++ if (*de->d_name == '.')
++ continue;
++
++ if (driver->guests == NULL)
++ driver->guests = guest = calloc(1, sizeof(struct vserver_guest));
++ else {
++ guest->next = calloc(1, sizeof(struct vserver_guest));
++ guest = guest->next;
++ }
++
++ if (!guest) {
++ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,
++ "vserver_guest");
++ goto error;
++ }
++
++ guest->path = calloc(strlen(conf_dir) + 1 + strlen(de->d_name) + 1, sizeof(char));
++ if (!guest->path)
++ goto nomem;
++ sprintf(guest->path, "%s/%s", conf_dir, de->d_name);
++
++#define CHECK(x) \
++ if ((x) == -1) { \
++ goto parseerror; \
++ }
++#define DO_SCHED(type, var, file, bit) \
++ do { \
++ int ret; \
++ CHECK(ret = read ## type((var), de->d_name, (file))); \
++ if (ret == 0) \
++ guest->sched.set_mask |= (bit); \
++ } while (0)
++
++ /* Parse simple values */
++ CHECK(readInt(&guest->xid, de->d_name, "context"));
++ CHECK(readStr(guest->name, sizeof(guest->name), de->d_name, "name"));
++ CHECK(readStr(guest->uts.hostname, sizeof(guest->uts.hostname), de->d_name,
++ "uts/nodename"));
++ CHECK(readStr(guest->uts.machine, sizeof(guest->uts.machine), de->d_name,
++ "uts/machine"));
++ CHECK(readStr(guest->uts.release, sizeof(guest->uts.release), de->d_name,
++ "uts/release"));
++ CHECK(readStr(guest->uts.version, sizeof(guest->uts.version), de->d_name,
++ "uts/version"));
++ CHECK(readStr(mark, sizeof(mark), de->d_name, "apps/init/mark"));
++
++ DO_SCHED(Int, &guest->sched.fill_rate, "sched/fill-rate",
++ VC_VXSM_FILL_RATE);
++ DO_SCHED(Int, &guest->sched.interval, "sched/interval",
++ VC_VXSM_INTERVAL);
++ DO_SCHED(Int, &guest->sched.fill_rate2, "sched/fill-rate2",
++ VC_VXSM_FILL_RATE2);
++ DO_SCHED(Int, &guest->sched.interval2, "sched/interval2",
++ VC_VXSM_INTERVAL2);
++ DO_SCHED(Int, &guest->sched.tokens_min, "sched/tokens-min",
++ VC_VXSM_TOKENS_MIN);
++ DO_SCHED(Int, &guest->sched.tokens_max, "sched/tokens-max",
++ VC_VXSM_TOKENS_MAX);
++ DO_SCHED(Int, &guest->sched.priority_bias, "sched/priority-bias",
++ VC_VXSM_PRIO_BIAS);
++ if (readBool(&tmp, de->d_name, "sched/idle-time") == 0) {
++ if (tmp)
++ guest->sched.set_mask |= VC_VXSM_IDLE_TIME;
++ }
++
++ CHECK(readLong(&guest->rss_hard, de->d_name, "rlimits/rss.hard"));
++
++ /* Generate a UUID if one doesn't already exist */
++ switch (readStr(uuidstr, sizeof(uuidstr), de->d_name, "uuid")) {
++ case 1:
++ CHECK(virUUIDGenerate(guest->uuid));
++ virUUIDFormat(guest->uuid, uuidstr);
++ CHECK(vserverWriteToConfig(guest, "uuid", "%s\n", uuidstr));
++ break;
++ case 0:
++ CHECK(virUUIDParse(uuidstr, guest->uuid));
++ break;
++ case -1:
++ goto parseerror;
++ }
++
++ /* Parse interfaces */
++ if (parseInterfaces(guest, "interfaces") == -1)
++ goto parseerror;
++
++ /* Parse fstab */
++ if (parseFstab(guest, "fstab") == -1)
++ goto parseerror;
++
++ /* Make sure the guest has the / directory in the disk output */
++ do {
++ struct vserver_fstab *ent;
++ int has_root = 0;
++ for (ent = guest->fstab; ent; ent = ent->next) {
++ if (strcmp(ent->target, "/") == 0) {
++ has_root = 1;
++ break;
++ }
++ }
++ if (!has_root) {
++ char vdir[strlen(de->d_name) + sizeof("/vdir")];
++
++ ent = calloc(1, sizeof(*ent));
++ if (!ent)
++ goto nomem;
++
++ sprintf(vdir, "%s/vdir", de->d_name);
++ ent->source = realpath(vdir, NULL);
++
++ ent->flags = VSERVER_FSTAB_SHOW;
++ ent->source_type = vserverFindSourceType("/");
++ ent->target = strdup("/");
++ ent->fstype = strdup("auto");
++ ent->options = strdup("defaults");
++ if (!ent->source || !ent->target || !ent->fstype || !ent->options)
++ goto nomem;
++ ent->next = guest->fstab;
++ guest->fstab = ent;
++ }
++ } while (0);
++#undef DO_SCHED
++#undef CHECK
++
++ if (STREQ(mark, "default"))
++ guest->autostart = 1;
++ if (vserverContextIsRunning(guest->path)) {
++ struct vc_ctx_flags flags;
++ if (vc_get_cflags(guest->xid, &flags) == 0 &&
++ (flags.flagword & VC_VXF_SCHED_PAUSE))
++ guest->status = VIR_DOMAIN_PAUSED;
++ else
++ guest->status = VIR_DOMAIN_RUNNING;
++ driver->active_guests++;
++ }
++ else {
++ guest->status = VIR_DOMAIN_SHUTOFF;
++ driver->inactive_guests++;
++ }
++ }
++
++ closedir(dp);
++ if (fchdir(cwd) == -1 || close(cwd) == -1) {
++ /* do nothing, we succeeded with everything else... */
++ }
++ driver->initialized = 1;
++
++ return VIR_DRV_OPEN_SUCCESS;
++
++nomem:
++ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL);
++ goto error;
++parseerror:
++ vserverError(conn, NULL, NULL, VIR_ERR_PARSE_FAILED, de->d_name);
++error:
++ if (dp)
++ closedir(dp);
++
++ if (fchdir(cwd) == -1 || close(cwd) == -1) {
++ /* we're already failing, nothing to do */
++ }
++ return VIR_DRV_OPEN_ERROR;
++}
++
++#endif
+--- libvirt-0.4.0.orig/src/vserver/vserver_conf.h 1970-01-01 01:00:00.000000000 +0100
++++ libvirt-0.4.0.vserver/src/vserver/vserver_conf.h 2008-01-05 02:10:20.000000000 +0100
+@@ -0,0 +1,36 @@
++/*
++ * Configuration handling for Linux-VServer guests
++ *
++ * Copyright (C) 2007-2008 Daniel Hokka Zakrisson
++ *
++ * 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 Hokka Zakrisson <daniel hozac com>
++ */
++
++#ifdef WITH_VSERVER
++
++/* Kind of a hack */
++#ifdef IN_VSERVER
++int vserverWriteToConfig(struct vserver_guest *guest, const char *filename,
++ const char *format, ...);
++int vserverWriteGuestToConfig(struct vserver_guest *guest);
++virDrvOpenStatus vserverInitializeDriver(virConnectPtr conn,
++ struct vserver_driver *driver,
++ const char *path);
++const char *vserverFindSourceType(const char *source);
++#endif
++
++#endif
+diff -Nurp libvirt-0.4.0.orig/src/vserver_driver.c libvirt-0.4.0.vserver/src/vserver_driver.c
+--- libvirt-0.4.0.orig/src/vserver_driver.c 1970-01-01 01:00:00.000000000 +0100
++++ libvirt-0.4.0.vserver/src/vserver_driver.c 2008-01-09 22:43:23.000000000 +0100
+@@ -0,0 +1,1625 @@
++/*
++ * Core driver for managing Linux-VServer guests
++ *
++ * Copyright (C) 2007-2008 Daniel Hokka Zakrisson
++ *
++ * 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 Hokka Zakrisson <daniel hozac com>
++ */
++
++#ifdef WITH_VSERVER
++
++#define _GNU_SOURCE
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <string.h>
++#include <fcntl.h>
++#include <dirent.h>
++#include <sys/wait.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <arpa/inet.h>
++#include <net/if.h>
++#include <sys/syscall.h>
++
++#include <libxml/uri.h>
++#include <libxml/xpath.h>
++#include <libxml/tree.h>
++
++#include <libvirt/virterror.h>
++
++#define IN_VSERVER 1
++#include "internal.h"
++#include "vserver_driver.h"
++#include "vserver_conf.h"
++#include "buf.h"
++#include "uuid.h"
++#include "xml.h"
++#include "nodeinfo.h"
++
++#define GET_DOMAIN(dom, ret) \
++ struct vserver_driver *driver = (struct vserver_driver *) \
++ (dom)->conn->privateData; \
++ struct vserver_guest *guest = getGuestByUUID(driver, (dom)->uuid); \
++ \
++ if (!guest) { \
++ vserverError((dom)->conn, (dom), NULL, VIR_ERR_INVALID_ARG, \
++ __FUNCTION__); \
++ return (ret); \
++ }
++
++#ifndef MNT_DETACH
++# define MNT_DETACH 0x00000002
++#endif
++
++static int PAGE_SHIFT_TO_KIBI = 2;
++
++static inline int sys_umount(const char *path, int flags)
++{
++ return syscall(__NR_umount2, path, flags);
++}
++
++static inline struct vserver_guest *
++getGuestByID(struct vserver_driver *driver,
++ int id)
++{
++ struct vserver_guest *res;
++ for (res = driver->guests; res; res = res->next) {
++ if (res->xid == id)
++ break;
++ }
++ return res;
++}
++
++static inline struct vserver_guest *
++getGuestByUUID(struct vserver_driver *driver,
++ const unsigned char *uuid)
++{
++ struct vserver_guest *res;
++ for (res = driver->guests; res; res = res->next) {
++ if (memcmp(res->uuid, uuid, VIR_UUID_BUFLEN) == 0)
++ break;
++ }
++ return res;
++}
++
++static inline struct vserver_guest *
++getGuestByName(struct vserver_driver *driver,
++ const char *name)
++{
++ struct vserver_guest *res;
++ for (res = driver->guests; res; res = res->next) {
++ if (STREQ(res->name, name))
++ break;
++ }
++ return res;
++}
++
++void
++vserverError(virConnectPtr con,
++ virDomainPtr dom,
++ virNetworkPtr net,
++ virErrorNumber error,
++ const char *info)
++{
++ const char *errmsg;
++
++ if (error == VIR_ERR_OK)
++ return;
++
++ errmsg = __virErrorMsg(error, info);
++ __virRaiseError(con, dom, net, VIR_FROM_VSERVER, error, VIR_ERR_ERROR,
++ errmsg, info, NULL, 0, 0, errmsg, info, 0);
++}
++
++/* like execl, but uses /dev/null and handles forking/waiting/etc. */
++int
++vserverRunCommand(int do_daemon, const char *cmd, ...)
++{
++ pid_t pid;
++ va_list va;
++ char **argv;
++ int i, argc;
++ sighandler_t sigchld;
++ int ret;
++
++ va_start(va, cmd);
++ argc = 15;
++ argv = calloc(argc, sizeof(*argv));
++ argv[0] = (char *) cmd;
++ for (i = 1; (argv[i] = va_arg(va, char *)) != NULL; i++) {
++ if (i == argc-1) {
++ argc += 5;
++ argv = realloc(argv, sizeof(*argv) * argc);
++ }
++ }
++
++ va_end(va);
++
++ /* XXX: This is bad, since another child could die
++ * between here and where we restore it */
++ sigchld = signal(SIGCHLD, SIG_DFL);
++ if ((pid = fork()) == 0) {
++ int fd;
++ if (do_daemon) {
++ pid_t not_a_zombie;
++
++ if (setsid() == -1)
++ goto error;
++
++ not_a_zombie = fork();
++ if (not_a_zombie == -1)
++ goto error;
++ else if (not_a_zombie > 0)
++ _exit(0);
++ }
++ if ((fd = open("/dev/null", O_RDWR)) == -1)
++ goto error;
++ if (dup2(fd, 0) == -1 || dup2(fd, 1) == -1 || dup2(fd, 2) == -1)
++ goto error;
++ if (fd > 2 && close(fd) == -1)
++ goto error;
++ execvp(cmd, argv);
++ error:
++ _exit(1);
++ }
++ else if (pid == -1) {
++ ret = -1;
++ }
++ else {
++ int status;
++ if (waitpid(pid, &status, 0) == -1)
++ ret = -1;
++ else if (WEXITSTATUS(status) != 0)
++ ret = 1;
++ else
++ ret = 0;
++ }
++
++ signal(SIGCHLD, sigchld);
++ return ret;
++}
++
++int
++vserverContextIsRunning(const char *path)
++{
++ return vc_getVserverCtx(path, vcCFG_AUTO, false, 0, vcCTX_XID) != VC_NOCTX;
++}
++
++static void
++vserverSetPagesize(void)
++{
++ long page_size = sysconf(_SC_PAGESIZE);
++ PAGE_SHIFT_TO_KIBI = page_size / 1024;
++}
++
++static virDrvOpenStatus
++vserverOpen(virConnectPtr conn, xmlURIPtr uri,
++ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
++ int flags ATTRIBUTE_UNUSED)
++{
++ virDrvOpenStatus ret;
++ struct vserver_driver *driver;
++
++ if (!uri)
++ return VIR_DRV_OPEN_DECLINED;
++
++ if (getuid() != 0)
++ return VIR_DRV_OPEN_DECLINED;
++
++ if (!uri->scheme || STRNEQ(uri->scheme, "vserver"))
++ return VIR_DRV_OPEN_DECLINED;
++
++ if (uri->server)
++ return VIR_DRV_OPEN_DECLINED;
++
++ /* nothing else supported right now */
++ if (strncmp(uri->path, "/system", 7) != 0)
++ return VIR_DRV_OPEN_DECLINED;
++
++ /* make sure it's a Linux-VServer kernel */
++ if (vc_get_version() == -1)
++ return VIR_DRV_OPEN_DECLINED;
++
++ if (!conn->privateData)
++ conn->privateData = calloc(1, sizeof(struct vserver_driver));
++
++ ret = vserverInitializeDriver(conn, conn->privateData, uri->path + 7);
++ if (ret == VIR_DRV_OPEN_SUCCESS) {
++ driver = conn->privateData;
++ driver->uri = xmlSaveUri(uri);
++ }
++ else {
++ free(conn->privateData);
++ }
++
++ vserverSetPagesize();
++
++ return ret;
++}
++
++static void
++freeFstab(struct vserver_fstab *ent)
++{
++ free(ent->source);
++ free(ent->target);
++ free(ent->fstype);
++ free(ent->options);
++ free(ent);
++}
++
++static void
++freeGuest(struct vserver_guest *guest)
++{
++ struct vserver_ip *ip, *pip = NULL;
++ struct vserver_fstab *ent, *pent = NULL;
++ for (ip = guest->ips; ip; ip = ip->next) {
++ if (pip)
++ free(pip);
++ pip = ip;
++ }
++ if (pip)
++ free(pip);
++ for (ent = guest->fstab; ent; ent = ent->next) {
++ if (pent)
++ freeFstab(pent);
++ pent = ent;
++ }
++ if (pent)
++ freeFstab(pent);
++ free(guest->path);
++ free(guest);
++}
++
++static int
++vserverClose(virConnectPtr conn)
++{
++ struct vserver_driver *driver = conn->privateData;
++ struct vserver_guest *guest, *pguest;
++
++ if (!driver || !driver->initialized)
++ return 0;
++
++ for (guest = driver->guests, pguest = NULL; guest; guest = guest->next) {
++ if (pguest)
++ freeGuest(pguest);
++ pguest = guest;
++ }
++ if (pguest)
++ freeGuest(pguest);
++
++ xmlFree(driver->uri);
++ free(driver);
++ conn->privateData = NULL;
++
++ return 0;
++}
++
++static const char *
++vserverGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
++{
++ return "Linux-VServer";
++}
++
++static int
++vserverGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *version)
++{
++ *version = 1;
++ return 0;
++}
++
++static char *
++vserverGetHostname(virConnectPtr conn)
++{
++ char *ret;
++
++ ret = calloc(VSERVER_UTS_MAX + 1, sizeof(char));
++ if (!ret) {
++ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "gethostname");
++ return NULL;
++ }
++
++ if (gethostname(ret, VSERVER_UTS_MAX) == -1) {
++ free(ret);
++ vserverError(conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, strerror(errno));
++ return NULL;
++ }
++
++ return ret;
++}
++
++static char *
++vserverGetURI(virConnectPtr conn)
++{
++ struct vserver_driver *driver = conn->privateData;
++ return (char *) xmlStrdup(driver->uri);
++}
++
++static int
++vserverNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo)
++{
++ return virNodeInfoPopulate(conn, nodeinfo);
++}
++
++static int
++vserverListDomains(virConnectPtr conn, int *ids, int nids)
++{
++ struct vserver_driver *driver = conn->privateData;
++ struct vserver_guest *guest;
++ int i;
++
++ for (guest = driver->guests, i = 0; guest && i < nids;
++ guest = guest->next) {
++ if (guest->status != VIR_DOMAIN_SHUTOFF)
++ ids[i++] = guest->xid;
++ }
++
++ return i;
++}
++
++static int
++vserverNumOfDomains(virConnectPtr conn)
++{
++ struct vserver_driver *driver = conn->privateData;
++
++ return driver->active_guests;
++}
++
++static virDomainPtr
++vserverDomainLookupByID(virConnectPtr conn, int id)
++{
++ struct vserver_driver *driver = conn->privateData;
++ struct vserver_guest *guest;
++ virDomainPtr domain;
++
++ if ((guest = getGuestByID(driver, id)) == NULL) {
++ vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
++ _("No domain by that ID found"));
++ return NULL;
++ }
++
++ domain = virGetDomain(conn, guest->name, guest->uuid);
++ if (!domain) {
++ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
++ return NULL;
++ }
++
++ if (vserverIsRunning(guest))
++ domain->id = guest->xid;
++
++ return domain;
++}
++
++static virDomainPtr
++vserverDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
++{
++ struct vserver_driver *driver = conn->privateData;
++ struct vserver_guest *guest;
++ virDomainPtr domain;
++
++ if ((guest = getGuestByUUID(driver, uuid)) == NULL) {
++ vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
++ _("No domain by that UUID found"));
++ return NULL;
++ }
++
++ domain = virGetDomain(conn, guest->name, guest->uuid);
++ if (!domain) {
++ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
++ return NULL;
++ }
++
++ if (vserverIsRunning(guest))
++ domain->id = guest->xid;
++
++ return domain;
++}
++
++static virDomainPtr
++vserverDomainLookupByName(virConnectPtr conn, const char *name)
++{
++ struct vserver_driver *driver = conn->privateData;
++ struct vserver_guest *guest;
++ virDomainPtr domain;
++
++ if ((guest = getGuestByName(driver, name)) == NULL) {
++ vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
++ _("No domain by that name found"));
++ return NULL;
++ }
++
++ domain = virGetDomain(conn, guest->name, guest->uuid);
++ if (!domain) {
++ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
++ return NULL;
++ }
++
++ if (vserverIsRunning(guest))
++ domain->id = guest->xid;
++
++ return domain;
++}
++
++static int
++vserverDomainSuspend(virDomainPtr domain)
++{
++ struct vc_ctx_flags flags = {
++ .flagword = VC_VXF_SCHED_PAUSE,
++ .mask = VC_VXF_SCHED_PAUSE,
++ };
++ GET_DOMAIN(domain, -1);
++
++ if (guest->status == VIR_DOMAIN_PAUSED)
++ return 0;
++ if (guest->status != VIR_DOMAIN_RUNNING) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_OPERATION_FAILED,
++ _("domain is not running"));
++ return -1;
++ }
++
++ if (vc_set_cflags(guest->xid, &flags) == -1) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++ strerror(errno));
++ return -1;
++ }
++ guest->status = VIR_DOMAIN_PAUSED;
++
++ return 0;
++}
++
++static int
++vserverDomainResume(virDomainPtr domain)
++{
++ struct vc_ctx_flags flags = {
++ .flagword = 0,
++ .mask = VC_VXF_SCHED_PAUSE,
++ };
++ GET_DOMAIN(domain, -1);
++
++ if (guest->status == VIR_DOMAIN_RUNNING)
++ return 0;
++ if (guest->status != VIR_DOMAIN_PAUSED) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_OPERATION_FAILED,
++ _("domain is not running"));
++ return -1;
++ }
++
++ if (vc_set_cflags(guest->xid, &flags) == -1) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++ strerror(errno));
++ return -1;
++ }
++ guest->status = VIR_DOMAIN_RUNNING;
++
++ return 0;
++}
++
++static int
++vserverDomainShutdown(virDomainPtr domain)
++{
++ GET_DOMAIN(domain, -1);
++
++ if (vserverRunCommand(1, PROG_VSERVER, guest->path, "stop", NULL) != 0) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++ "vserver stop");
++ return -1;
++ }
++
++ driver->active_guests--;
++ guest->status = VIR_DOMAIN_SHUTOFF;
++ driver->inactive_guests++;
++ return 0;
++}
++
++static int
++vserverDomainReboot(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED)
++{
++ GET_DOMAIN(domain, -1);
++
++ if (vserverRunCommand(1, PROG_VSERVER, guest->path, "restart", NULL) != 0) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++ "vserver restart");
++ return -1;
++ }
++
++ guest->status = VIR_DOMAIN_RUNNING;
++ return 0;
++}
++
++static int
++vserverDomainDestroy(virDomainPtr domain)
++{
++ GET_DOMAIN(domain, -1);
++
++ if (vserverDomainShutdown(domain) == -1)
++ return -1;
++
++ virFreeDomain(domain->conn, domain);
++
++ return 0;
++}
++
++static char *
++vserverDomainGetOSType(virDomainPtr domain ATTRIBUTE_UNUSED)
++{
++ return strdup("Linux");
++}
++
++static unsigned long
++vserverDomainGetMaxMemory(virDomainPtr domain)
++{
++ GET_DOMAIN(domain, (unsigned long) -1);
++
++ return guest->rss_hard << PAGE_SHIFT_TO_KIBI;
++}
++
++static int
++vserverDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
++{
++ struct vc_rlimit limit = {
++ .min = 0,
++ };
++ GET_DOMAIN(domain, -1);
++
++ guest->rss_hard = memory >> PAGE_SHIFT_TO_KIBI;
++ limit.soft = limit.hard = guest->rss_hard;
++ if (vserverIsRunning(guest) &&
++ vc_set_rlimit(guest->xid, RLIMIT_RSS, &limit) == -1) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR, strerror(errno));
++ return -1;
++ }
++
++ if (vserverWriteToConfig(guest, "rlimits/rss.hard", "%lu\n", guest->rss_hard) == -1) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++ strerror(errno));
++ return -1;
++ }
++
++ return 0;
++}
++
++static int
++vserverDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
++{
++ struct vc_sched_info sinfo = { .user_msec = 0, .sys_msec = 0 };
++ struct vc_rlimit_stat rss_stat = { .value = 0 };
++ GET_DOMAIN(domain, -1);
++
++ if (vserverIsRunning(guest)) {
++ if (vc_sched_info(guest->xid, &sinfo) == -1) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++ strerror(errno));
++ return -1;
++ }
++ if (vc_rlimit_stat(guest->xid, RLIMIT_RSS, &rss_stat) == -1) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++ strerror(errno));
++ return -1;
++ }
++ }
++
++ info->state = guest->status;
++ info->maxMem = guest->rss_hard << PAGE_SHIFT_TO_KIBI;
++ info->nrVirtCpu = -1;
++ info->memory = rss_stat.value;
++ info->cpuTime = (sinfo.user_msec + sinfo.sys_msec) * 1000000ULL;
++
++ return 0;
++}
++
++static char *
++vserverDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED)
++{
++ virBufferPtr buf;
++ char uuid[VIR_UUID_STRING_BUFLEN + 1];
++ struct vserver_ip *ip;
++ GET_DOMAIN(domain, NULL);
++
++ buf = virBufferNew(4096);
++ if (!buf)
++ goto no_memory;
++
++ virUUIDFormat(guest->uuid, uuid);
++ if (virBufferVSprintf(buf,
++"<domain type='vserver' id='%d'>\n"
++" <name>%s</name>\n"
++" <uuid>%s</uuid>\n"
++ , guest->xid, guest->name, uuid
++ ) < 0)
++ goto no_memory;
++ if (guest->rss_hard > 0)
++ if (virBufferVSprintf(buf, " <memory>%lu</memory>\n",
++ guest->rss_hard << PAGE_SHIFT_TO_KIBI) < 0)
++ goto no_memory;
++
++ if (virBufferVSprintf(buf, " <os>\n"
++ " <hostname>%s</hostname>\n"
++ , guest->uts.hostname) < 0)
++ goto no_memory;
++ if (virBufferVSprintf(buf, " <type") < 0)
++ goto no_memory;
++ if (*guest->uts.machine)
++ if (virBufferVSprintf(buf, " arch='%s'", guest->uts.machine) < 0)
++ goto no_memory;
++ if (virBufferVSprintf(buf, ">vserver</type>\n") < 0)
++ goto no_memory;
++ if (*guest->uts.release)
++ if (virBufferVSprintf(buf, " <release>%s</release>\n",
++ guest->uts.release) < 0)
++ goto no_memory;
++ if (*guest->uts.version)
++ if (virBufferVSprintf(buf, " <version>%s</version>\n",
++ guest->uts.version) < 0)
++ goto no_memory;
++ if (virBufferVSprintf(buf, " </os>\n"
++ " <devices>\n") < 0)
++ goto no_memory;
++
++ for (ip = guest->ips; ip; ip = ip->next) {
++ char addrbuf[128];
++ if (virBufferVSprintf(buf, " <interface type='ethernet'>\n"
++ " <ip prefix='%d'", ip->addr.vna_prefix) < 0)
++ goto no_memory;
++ if (*ip->interface)
++ if (virBufferVSprintf(buf, " interface='%s'", ip->interface) < 0)
++ goto no_memory;
++
++ switch (ip->addr.vna_type & (VC_NXA_TYPE_IPV4|VC_NXA_TYPE_IPV6)) {
++ case VC_NXA_TYPE_IPV4:
++ inet_ntop(AF_INET, &ip->addr.vna_v4_ip, addrbuf, sizeof(addrbuf));
++ if (virBufferVSprintf(buf, " address='%s'", addrbuf) < 0)
++ goto no_memory;
++ if (ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_RANGE)) {
++ inet_ntop(AF_INET, &ip->addr.vna_v4_ip2, addrbuf, sizeof(addrbuf));
++ if (virBufferVSprintf(buf, " address2='%s' type='range'", addrbuf) < 0)
++ goto no_memory;
++ }
++ if (ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_MASK)) {
++ if (virBufferVSprintf(buf, " type='mask'") < 0)
++ goto no_memory;
++ }
++ if (ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_RANGE) ||
++ ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_MASK)) {
++ inet_ntop(AF_INET, &ip->addr.vna_v4_mask, addrbuf, sizeof(addrbuf));
++ if (virBufferVSprintf(buf, " mask='%s'", addrbuf) < 0)
++ goto no_memory;
++ }
++ break;
++
++ case VC_NXA_TYPE_IPV6:
++ inet_ntop(AF_INET6, &ip->addr.vna_v6_ip, addrbuf, sizeof(addrbuf));
++ if (virBufferVSprintf(buf, " address='%s'", addrbuf) < 0)
++ goto no_memory;
++ if (ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_RANGE)) {
++ inet_ntop(AF_INET6, &ip->addr.vna_v6_ip2, addrbuf, sizeof(addrbuf));
++ if (virBufferVSprintf(buf, " address2='%s' type='range'", addrbuf) < 0)
++ goto no_memory;
++ }
++ if (ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_MASK)) {
++ if (virBufferVSprintf(buf, " type='mask'") < 0)
++ goto no_memory;
++ }
++ if (ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_RANGE) ||
++ ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_MASK)) {
++ inet_ntop(AF_INET6, &ip->addr.vna_v6_mask, addrbuf, sizeof(addrbuf));
++ if (virBufferVSprintf(buf, " mask='%s'", addrbuf) < 0)
++ goto no_memory;
++ }
++ break;
++ }
++
++ if (virBufferVSprintf(buf, " />\n"
++ " </interface>\n") < 0)
++ goto no_memory;
++ }
++
++ if (guest->fstab) {
++ struct vserver_fstab *ent;
++ for (ent = guest->fstab; ent; ent = ent->next) {
++ /* Skip things like proc */
++ if (!(ent->flags & VSERVER_FSTAB_SHOW))
++ continue;
++ if (virBufferVSprintf(buf, " <disk type='%s' device='directory'>\n"
++ " <source %s='%s' type='%s' options='%s'/>\n"
++ " <target directory='%s'/>\n"
++ " </disk>\n",
++ ent->source_type,
++ (strcmp(ent->source_type, "block") == 0 ?
++ "dev" : ent->source_type),
++ ent->source,
++ ent->fstype,
++ ent->options,
++ ent->target) < 0)
++ goto no_memory;
++ }
++ }
++
++ if (virBufferVSprintf(buf, " </devices>\n"
++ "</domain>\n") < 0)
++ goto no_memory;
++
++ return virBufferContentAndFree(buf);
++
++no_memory:
++ if (buf)
++ virBufferFree(buf);
++ vserverError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY,
++ "xml");
++ return NULL;
++}
++
++static int
++vserverParseIP(struct vserver_ip *ip, xmlNodePtr node)
++{
++ xmlChar *value;
++ char *endptr;
++
++ value = xmlGetProp(node, BAD_CAST "address");
++ if (!value)
++ goto err;
++ if (inet_pton(AF_INET6, (char *) value, &ip->addr.vna_v6_ip) > 0)
++ ip->addr.vna_type = VC_NXA_TYPE_IPV6;
++ else if (inet_pton(AF_INET, (char *) value, &ip->addr.vna_v4_ip) > 0)
++ ip->addr.vna_type = VC_NXA_TYPE_IPV4;
++ else
++ goto err;
++
++ value = xmlGetProp(node, BAD_CAST "prefix");
++ if (!value)
++ goto err;
++ ip->addr.vna_prefix = strtol((char *) value, &endptr, 0);
++ if (*endptr)
++ goto err;
++ xmlFree(value);
++
++ value = xmlGetProp(node, BAD_CAST "type");
++ if (!value)
++ ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
++ else {
++ if (xmlStrcasecmp(value, BAD_CAST "address") == 0)
++ ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
++ else if (xmlStrcasecmp(value, BAD_CAST "mask") == 0)
++ ip->addr.vna_type |= VC_NXA_TYPE_MASK;
++ else if (xmlStrcasecmp(value, BAD_CAST "range") == 0)
++ ip->addr.vna_type |= VC_NXA_TYPE_RANGE;
++ else
++ goto err;
++ xmlFree(value);
++ }
++
++ value = xmlGetProp(node, BAD_CAST "interface");
++ if (value) {
++ strncpy(ip->interface, (char *) value, IFNAMSIZ);
++ xmlFree(value);
++ }
++
++ return 0;
++
++err:
++ if (value)
++ xmlFree(value);
++ return -1;
++}
++
++static const char *
++diskTypeToAttr(const char *type)
++{
++ return (strcmp(type, "block") == 0 ? "dev" : type);
++}
++
++static int
++vserverParseDisk(struct vserver_fstab *ent, xmlNodePtr node)
++{
++ xmlChar *type = NULL, *value = NULL;
++ xmlNodePtr iter, source = NULL, target = NULL;
++
++ for (iter = node->children; iter && (!source || !target); iter = iter->next) {
++ if (iter->type != XML_ELEMENT_NODE)
++ continue;
++ if (xmlStrEqual(iter->name, BAD_CAST "source"))
++ source = iter;
++ else if (xmlStrEqual(iter->name, BAD_CAST "target"))
++ target = iter;
++ }
++ if (!target || !source)
++ goto err;
++
++ value = xmlGetProp(node, BAD_CAST "device");
++ if (!value || !xmlStrEqual(value, BAD_CAST "directory"))
++ goto err;
++ xmlFree(value);
++
++ ent->target = (char *) xmlGetProp(target, BAD_CAST "directory");
++ if (!value)
++ goto err;
++
++ type = xmlGetProp(node, BAD_CAST "type");
++ if (!type)
++ goto err;
++ ent->source = (char *) xmlGetProp(source, BAD_CAST diskTypeToAttr((char *) type));
++ xmlFree(type);
++ if (!ent->source)
++ goto err;
++
++ ent->source_type = vserverFindSourceType(ent->source);
++ if (!ent->source_type)
++ goto err;
++
++ ent->fstype = (char *) xmlGetProp(source, BAD_CAST "type");
++ if (!ent->fstype)
++ ent->fstype = strdup("auto");
++
++ ent->options = (char *) xmlGetProp(source, BAD_CAST "options");
++ if (!ent->options) {
++ if (strcmp(ent->source_type, "file") == 0)
++ ent->options = strdup("defaults,loop");
++ else
++ ent->options = strdup("defaults");
++ }
++
++ ent->flags = VSERVER_FSTAB_SHOW | VSERVER_FSTAB_OUTPUT;
++
++ return 0;
++
++err:
++ if (ent->fstype)
++ xmlFree(ent->fstype);
++ if (ent->source)
++ xmlFree(ent->source);
++ if (ent->target)
++ xmlFree(ent->target);
++ if (value)
++ xmlFree(value);
++ return -1;
++}
++
++static int
++vserverParseXML(struct vserver_guest *guest, xmlDocPtr doc)
++{
++ xmlNodePtr root;
++ xmlXPathContextPtr xpath = NULL;
++ xmlXPathObjectPtr obj;
++ char *str;
++ long l_tmp;
++
++ /* FIXME: This could use some better error reporting... */
++ root = xmlDocGetRootElement(doc);
++ if (!root || !xmlStrEqual(root->name, BAD_CAST "domain"))
++ goto err;
++
++ xpath = xmlXPathNewContext(doc);
++ if (!xpath)
++ goto err;
++
++ if (virXPathLong("string(/domain[1]/@id)", xpath, &l_tmp) != 0)
++ goto err;
++ guest->xid = (int) l_tmp;
++
++ str = virXPathString("string(/domain/name[1])", xpath);
++ if (!str)
++ goto err;
++ strncpy(guest->name, str, VSERVER_NAME_MAX - 1);
++
++ str = virXPathString("string(/domain/uuid[1])", xpath);
++ if (!str) {
++ if (virUUIDGenerate(guest->uuid) != 0)
++ goto err;
++ }
++ else if (virUUIDParse(str, guest->uuid) < 0)
++ goto err;
++
++ guest->rss_hard = 0;
++ if (virXPathLong("string(/domain/memory[1])", xpath, (long *) &guest->rss_hard) == -2)
++ goto err;
++ guest->rss_hard >>= PAGE_SHIFT_TO_KIBI;
++
++ str = virXPathString("string(/domain/os[1]/hostname[1])", xpath);
++ if (str)
++ strncpy(guest->uts.hostname, str, VSERVER_UTS_MAX - 1);
++
++ str = virXPathString("string(/domain/os[1]/type[1]/@arch)", xpath);
++ if (str)
++ strncpy(guest->uts.machine, str, VSERVER_UTS_MAX - 1);
++
++ str = virXPathString("string(/domain/os[1]/release[1])", xpath);
++ if (str)
++ strncpy(guest->uts.machine, str, VSERVER_UTS_MAX - 1);
++
++ str = virXPathString("string(/domain/os[1]/version[1])", xpath);
++ if (str)
++ strncpy(guest->uts.machine, str, VSERVER_UTS_MAX - 1);
++
++ str = virXPathString("string(/domain/container/initstyle[1]/@type)", xpath);
++ guest->initstyle = VSERVER_INIT_SYSV;
++ if (str) {
++ if (strcmp(str, "plain") == 0)
++ guest->initstyle = VSERVER_INIT_PLAIN;
++ else if (strcmp(str, "gentoo") == 0)
++ guest->initstyle = VSERVER_INIT_GENTOO;
++ else if (strcmp(str, "minit") == 0)
++ guest->initstyle = VSERVER_INIT_MINIT;
++ else if (strcmp(str, "sysv") == 0)
++ guest->initstyle = VSERVER_INIT_SYSV;
++ }
++
++ obj = xmlXPathEval(BAD_CAST "/domain/devices[1]/interface/ip", xpath);
++ if (obj != NULL && obj->type == XPATH_NODESET && obj->nodesetval != NULL &&
++ obj->nodesetval->nodeNr > 0) {
++ int i;
++ struct vserver_ip *ip = NULL;
++
++ for (i = 0; i < obj->nodesetval->nodeNr; i++) {
++ if (ip == NULL)
++ guest->ips = ip = calloc(1, sizeof(*ip));
++ else {
++ ip->next = calloc(1, sizeof(*ip));
++ ip = ip->next;
++ }
++
++ if (vserverParseIP(ip, obj->nodesetval->nodeTab[i]) == -1)
++ goto nodeset_err;
++ }
++ }
++ if (obj)
++ xmlXPathFreeObject(obj);
++
++ obj = xmlXPathEval(BAD_CAST "/domain/devices[1]/disk", xpath);
++ if (obj != NULL && obj->type == XPATH_NODESET && obj->nodesetval != NULL &&
++ obj->nodesetval->nodeNr > 0) {
++ int i;
++ struct vserver_fstab *ent = NULL;
++
++ for (i = 0; i < obj->nodesetval->nodeNr; i++) {
++ if (ent == NULL)
++ guest->fstab = ent = calloc(1, sizeof(*ent));
++ else {
++ ent->next = calloc(1, sizeof(*ent));
++ ent = ent->next;
++ }
++
++ if (vserverParseDisk(ent, obj->nodesetval->nodeTab[i]) == -1)
++ goto nodeset_err;
++ }
++ }
++ if (obj)
++ xmlXPathFreeObject(obj);
++
++ xmlXPathFreeContext(xpath);
++ xpath = NULL;
++
++ return 0;
++
++nodeset_err:
++ xmlXPathFreeObject(obj);
++err:
++ if (xpath)
++ xmlXPathFreeContext(xpath);
++ return -1;
++}
++
++static virDomainPtr
++vserverDomainDefineXML(virConnectPtr conn, const char *xml)
++{
++ struct vserver_driver *driver = conn->privateData;
++ struct vserver_guest *guest, *tail;
++ virDomainPtr domain;
++ xmlDocPtr doc;
++ char buf[128];
++
++ if ((guest = calloc(1, sizeof(struct vserver_guest))) == NULL) {
++ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "vserver_guest");
++ return NULL;
++ }
++
++ if ((doc = xmlReadDoc(BAD_CAST xml, "domain.xml", NULL,
++ XML_PARSE_NOENT | XML_PARSE_NONET |
++ XML_PARSE_NOWARNING | XML_PARSE_NOERROR)) == NULL) {
++ vserverError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain"));
++ free(guest);
++ return NULL;
++ }
++
++ if (vserverParseXML(guest, doc) == -1) {
++ vserverError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain"));
++ xmlFreeDoc(doc);
++ free(guest);
++ return NULL;
++ }
++
++ xmlFreeDoc(doc);
++
++ guest->path = calloc(sizeof(VSERVER_CONF_DIR "/") + strlen(guest->name), sizeof(char));
++ sprintf(guest->path, VSERVER_CONF_DIR "/%s", guest->name);
++ guest->status = VIR_DOMAIN_SHUTOFF;
++ if (vserverRunCommand(0, PROG_VSERVER, guest->name, "build", "-m",
++ "skeleton", "--confdir", guest->path, NULL) != 0) {
++ vserverError(conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, "vserver build");
++ free(guest);
++ return NULL;
++ }
++ virUUIDFormat(guest->uuid, buf);
++ if (vserverWriteGuestToConfig(guest) == -1) {
++ vserverError(conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, "vserverWriteToConfig");
++ free(guest);
++ return NULL;
++ }
++
++ /* add it to the list */
++ for (tail = driver->guests; tail && tail->next; tail = tail->next)
++ ;
++ if (!tail)
++ driver->guests = guest;
++ else
++ tail->next = guest;
++
++ driver->inactive_guests++;
++
++ domain = virGetDomain(conn, guest->name, guest->uuid);
++ if (!domain)
++ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
++
++ return domain;
++}
++
++static int
++vserverListDefinedDomains(virConnectPtr conn, char **const names,
++ int maxnames)
++{
++ struct vserver_driver *driver = conn->privateData;
++ struct vserver_guest *guest;
++ int i = 0;
++
++ for (guest = driver->guests; guest && i < maxnames; guest = guest->next) {
++ if (guest->status == VIR_DOMAIN_SHUTOFF) {
++ if ((names[i++] = strdup(guest->name)) == NULL) {
++ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "names");
++ return -1;
++ }
++ }
++ }
++
++ return i;
++}
++
++static int
++vserverNumOfDefinedDomains(virConnectPtr conn)
++{
++ struct vserver_driver *driver = conn->privateData;
++
++ return driver->inactive_guests;
++}
++
++static int
++vserverDomainCreate(virDomainPtr domain)
++{
++ GET_DOMAIN(domain, -1);
++
++ if (vserverRunCommand(1, PROG_VSERVER, guest->path, "start", NULL) != 0) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++ "vserver start");
++ return -1;
++ }
++
++ driver->inactive_guests--;
++ guest->status = VIR_DOMAIN_RUNNING;
++ driver->active_guests++;
++ return 0;
++}
++
++static virDomainPtr
++vserverDomainCreateLinux(virConnectPtr conn, const char *xml,
++ unsigned int flags ATTRIBUTE_UNUSED)
++{
++ virDomainPtr domain;
++
++ domain = vserverDomainDefineXML(conn, xml);
++ if (!domain)
++ return NULL;
++
++ if (vserverDomainCreate(domain) == -1)
++ return NULL;
++
++ return domain;
++}
++
++static int
++vserverDomainUndefine(virDomainPtr domain)
++{
++ struct vserver_guest *prev;
++ GET_DOMAIN(domain, -1);
++
++ for (prev = driver->guests; prev; prev = prev->next) {
++ if (prev->next == guest)
++ break;
++ }
++ if (!prev) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
++ _("domain not found"));
++ return -1;
++ }
++ if (vserverIsRunning(guest)) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG,
++ _("domain is running"));
++ return -1;
++ }
++
++ driver->inactive_guests--;
++ prev->next = guest->next;
++ /* XXX: deletes the domain's contents as well */
++ vserverRunCommand(0, PROG_VSERVER, "--silent", guest->path, "delete", NULL);
++ free(guest);
++
++ return 0;
++}
++
++static int
++doMount(int do_umount, struct vserver_guest *guest, struct vserver_fstab *ent)
++{
++ pid_t child;
++ int status;
++
++ if ((child = fork()) == 0) {
++ if (vc_enter_namespace(guest->xid, CLONE_NEWNS|CLONE_FS) == -1)
++ _exit(errno);
++ if (do_umount) {
++ if (sys_umount(ent->target, MNT_DETACH) == -1)
++ _exit(errno);
++ }
++ else {
++ char target[strlen(guest->path) + sizeof("/vdir/") + strlen(ent->target)];
++ sprintf(target, "%s/vdir/%s", guest->path, ent->target);
++ if (vserverRunCommand(0, "mount", "-t", ent->fstype, "-n", "-o",
++ ent->options, ent->source, target, NULL))
++ _exit(errno);
++ }
++ _exit(0);
++ }
++ else if (child == -1)
++ return -1;
++ else {
++ if (waitpid(child, &status, 0) == -1)
++ return -1;
++ if (WEXITSTATUS(status) != 0) {
++ errno = WEXITSTATUS(status);
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++static int
++vserverDomainHandleDevice(virDomainPtr domain, const char *xml, int attach)
++{
++ xmlDocPtr doc;
++ xmlNodePtr node;
++ GET_DOMAIN(domain, -1);
++
++ if ((doc = xmlReadDoc(BAD_CAST xml, "device.xml", NULL,
++ XML_PARSE_NOENT | XML_PARSE_NONET |
++ XML_PARSE_NOWARNING | XML_PARSE_NOERROR)) == NULL) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR, _("device"));
++ return -1;
++ }
++
++ node = xmlDocGetRootElement(doc);
++ if (node == NULL) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
++ _("missing root element"));
++ return -1;
++ }
++
++ if (xmlStrEqual(node->name, BAD_CAST "interface")) {
++ xmlNodePtr child;
++ struct vserver_ip *ip;
++
++ for (child = node->children; child; child = child->next) {
++ if (child->type != XML_ELEMENT_NODE)
++ continue;
++
++ /* This should be an only child, but who knows. */
++ if (xmlStrEqual(child->name, BAD_CAST "ip"))
++ break;
++ }
++ if (!child) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
++ _("no <ip> element found"));
++ return -1;
++ }
++
++ ip = calloc(1, sizeof(*ip));
++ if (vserverParseIP(ip, child) == -1) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
++ _("parsing IP failed"));
++ return -1;
++ }
++
++ if (attach) {
++ list_add_tail(guest->ips, ip);
++ if (vserverIsRunning(guest)) {
++ if (vc_net_add(guest->xid, &ip->addr) == -1) {
++ vserverError(domain->conn, domain, NULL,
++ VIR_ERR_SYSTEM_ERROR, strerror(errno));
++ return -1;
++ }
++ }
++ }
++
++ else /* detach */ {
++ struct vserver_ip *i, *p = NULL;
++ for (i = guest->ips; i; i = i->next) {
++ if (strcmp(ip->interface, i->interface) == 0 &&
++ memcmp(&ip->addr, &i->addr, sizeof(ip->addr)) == 0)
++ break;
++ p = i;
++ }
++ if (i) {
++ if (p)
++ p->next = i->next;
++ else
++ guest->ips = i->next;
++ if (vserverIsRunning(guest)) {
++ /* Not a lot of kernels support this, so don't fail. */
++ vc_net_remove(guest->xid, &ip->addr);
++ }
++ free(i);
++ }
++ free(ip);
++ }
++ }
++ else if (xmlStrEqual(node->name, BAD_CAST "disk")) {
++ struct vserver_fstab *ent = calloc(1, sizeof(*ent));
++ if (!ent) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY, NULL);
++ return -1;
++ }
++
++ if (vserverParseDisk(ent, node) == -1) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR, "disk");
++ return -1;
++ }
++
++ if (attach) {
++ list_add_tail(guest->fstab, ent);
++ if (vserverIsRunning(guest)) {
++ if (doMount(0, guest, ent) == -1) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++ strerror(errno));
++ return -1;
++ }
++ }
++ }
++
++ else /* detach */ {
++ struct vserver_fstab *i, *p = NULL;
++ for (i = guest->fstab; i; i = i->next) {
++ /* These are the fields we care about */
++ if (strcmp(ent->source, i->source) == 0 &&
++ strcmp(ent->target, i->target) == 0 &&
++ strcmp(ent->source_type, i->source_type) == 0)
++ break;
++ p = i;
++ }
++ if (i) {
++ if (p)
++ p->next = i->next;
++ else
++ guest->fstab = i->next;
++ if (vserverIsRunning(guest)) {
++ if (doMount(1, guest, ent) == -1) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++ strerror(errno));
++ return -1;
++ }
++ }
++ freeFstab(i);
++ }
++ freeFstab(ent);
++ }
++ }
++ else {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
++ _("unknown device type"));
++ return -1;
++ }
++
++ /* Both fstab and interfaces need a lot of writing, so write the whole thing */
++ if (vserverWriteGuestToConfig(guest) == -1) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_WRITE_FAILED, guest->name);
++ return -1;
++ }
++
++ xmlFreeDoc(doc);
++
++ return 0;
++}
++
++static int
++vserverDomainAttachDevice(virDomainPtr domain, const char *xml)
++{
++ return vserverDomainHandleDevice(domain, xml, 1);
++}
++
++static int
++vserverDomainDetachDevice(virDomainPtr domain, const char *xml)
++{
++ return vserverDomainHandleDevice(domain, xml, 0);
++}
++
++static int
++vserverDomainGetAutostart(virDomainPtr domain, int *autostart)
++{
++ GET_DOMAIN(domain, -1);
++
++ *autostart = guest->autostart;
++ return 0;
++}
++
++static int
++vserverDomainSetAutostart(virDomainPtr domain, int autostart)
++{
++ GET_DOMAIN(domain, -1);
++
++ if (vserverWriteToConfig(guest, "apps/init/mark",
++ (autostart ? "default\n" : "\n")) == -1) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_WRITE_FAILED,
++ "apps/init/mark");
++ return -1;
++ }
++ guest->autostart = autostart;
++ return 0;
++}
++
++static const struct {
++ unsigned int id;
++ const char *field;
++ int type;
++} sched_fields[] = {
++ { VC_VXSM_FILL_RATE, "fill_rate1", VIR_DOMAIN_SCHED_FIELD_UINT },
++ { VC_VXSM_INTERVAL, "interval1", VIR_DOMAIN_SCHED_FIELD_UINT },
++ { VC_VXSM_FILL_RATE2, "fill_rate2", VIR_DOMAIN_SCHED_FIELD_UINT },
++ { VC_VXSM_INTERVAL2, "interval2", VIR_DOMAIN_SCHED_FIELD_UINT },
++ { VC_VXSM_TOKENS_MIN, "tokens_min", VIR_DOMAIN_SCHED_FIELD_UINT },
++ { VC_VXSM_TOKENS_MAX, "tokens_max", VIR_DOMAIN_SCHED_FIELD_UINT },
++ { VC_VXSM_PRIO_BIAS, "prio_bias", VIR_DOMAIN_SCHED_FIELD_INT },
++ { VC_VXSM_IDLE_TIME, "idle_time", VIR_DOMAIN_SCHED_FIELD_BOOLEAN },
++ { 0, NULL, 0 }
++};
++
++static char *
++vserverDomainGetSchedulerType(virDomainPtr domain, int *nparams)
++{
++ char *ret;
++ int i;
++ GET_DOMAIN(domain, NULL);
++
++ ret = strdup(guest->sched.set_mask & VC_VXSM_IDLE_TIME ? "fair" : "hard");
++ if (!ret) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY,
++ _("scheduler"));
++ return NULL;
++ }
++
++ *nparams = 0;
++ for (i = 0; sched_fields[i].field != NULL; i++) {
++ /* only returns fields which are set */
++ if (guest->sched.set_mask & sched_fields[i].id)
++ (*nparams)++;
++ }
++
++ return ret;
++}
++
++static int
++vserverDomainGetSchedulerParams(virDomainPtr domain,
++ virSchedParameterPtr params,
++ int *nparams)
++{
++ int i, j;
++ GET_DOMAIN(domain, -1);
++
++ for (i = 0, j = 0; sched_fields[i].field != NULL && i < *nparams; i++) {
++ /* skip unset fields */
++ if (!(guest->sched.set_mask & sched_fields[i].id))
++ continue;
++
++ params[j].type = sched_fields[i].type;
++ strncpy(params[j].field, sched_fields[i].field, sizeof(params[j].field) - 1);
++ switch (sched_fields[i].id) {
++ case VC_VXSM_FILL_RATE:
++ params[j].value.ui = guest->sched.fill_rate;
++ break;
++ case VC_VXSM_INTERVAL:
++ params[j].value.ui = guest->sched.interval;
++ break;
++ case VC_VXSM_FILL_RATE2:
++ params[j].value.ui = guest->sched.fill_rate2;
++ break;
++ case VC_VXSM_INTERVAL2:
++ params[j].value.ui = guest->sched.interval2;
++ break;
++ case VC_VXSM_TOKENS_MIN:
++ params[j].value.ui = guest->sched.tokens_min;
++ break;
++ case VC_VXSM_TOKENS_MAX:
++ params[j].value.ui = guest->sched.tokens_max;
++ break;
++ case VC_VXSM_PRIO_BIAS:
++ params[j].value.i = guest->sched.priority_bias;
++ break;
++ case VC_VXSM_IDLE_TIME:
++ params[j].value.b = guest->sched.set_mask & VC_VXSM_IDLE_TIME;
++ break;
++ }
++ j++;
++ }
++ *nparams = j;
++
++ return 0;
++}
++
++static int
++vserverDomainSetSchedulerParams(virDomainPtr domain,
++ virSchedParameterPtr params,
++ int nparams)
++{
++ int i, j, cret;
++ GET_DOMAIN(domain, -1);
++
++ for (i = 0; i < nparams; i++) {
++ for (j = 0; sched_fields[j].field != NULL; j++) {
++ if (STREQ(sched_fields[j].field, params[i].field))
++ break;
++ }
++ if (sched_fields[j].field == NULL) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, "field");
++ return -1;
++ }
++ if (sched_fields[j].type != params[i].type) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, "type");
++ return -1;
++ }
++ switch (sched_fields[j].id) {
++ case VC_VXSM_FILL_RATE:
++ guest->sched.fill_rate = params[i].value.ui;
++ cret = vserverWriteToConfig(guest, "sched/fill-rate", "%u\n",
++ params[i].value.ui);
++ break;
++ case VC_VXSM_INTERVAL:
++ guest->sched.interval = params[i].value.ui;
++ cret = vserverWriteToConfig(guest, "sched/interval", "%u\n",
++ params[i].value.ui);
++ break;
++ case VC_VXSM_FILL_RATE2:
++ guest->sched.fill_rate2 = params[i].value.ui;
++ cret = vserverWriteToConfig(guest, "sched/fill-rate2", "%u\n",
++ params[i].value.ui);
++ break;
++ case VC_VXSM_INTERVAL2:
++ guest->sched.interval2 = params[i].value.ui;
++ cret = vserverWriteToConfig(guest, "sched/interval2", "%u\n",
++ params[i].value.ui);
++ break;
++ case VC_VXSM_TOKENS_MIN:
++ guest->sched.tokens_min = params[i].value.ui;
++ cret = vserverWriteToConfig(guest, "sched/tokens-min", "%u\n",
++ params[i].value.ui);
++ break;
++ case VC_VXSM_TOKENS_MAX:
++ guest->sched.tokens_max = params[i].value.ui;
++ cret = vserverWriteToConfig(guest, "sched/tokens-max", "%u\n",
++ params[i].value.ui);
++ break;
++ case VC_VXSM_PRIO_BIAS:
++ guest->sched.priority_bias = params[i].value.i;
++ cret = vserverWriteToConfig(guest, "sched/prio-bias", "%d\n",
++ params[i].value.i);
++ break;
++ case VC_VXSM_IDLE_TIME:
++ cret = vserverWriteToConfig(guest, "sched/idle-time", "%b",
++ params[i].value.b);
++ break;
++ default:
++ vserverError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
++ "Unknown scheduler parameter");
++ return -1;
++ }
++ if (cret == -1) {
++ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++ "vserverWriteToConfig");
++ return -1;
++ }
++ guest->sched.set_mask |= sched_fields[j].id;
++ }
++
++ return 0;
++}
++
++
++virDriver vserverDriver = {
++ VIR_DRV_VSERVER,
++ "Linux-VServer",
++ LIBVIR_VERSION_NUMBER,
++ vserverOpen,
++ vserverClose,
++ NULL, /* supports_feature */
++ vserverGetType,
++ vserverGetVersion,
++ vserverGetHostname,
++ vserverGetURI,
++ NULL, /* getMaxVcpus */
++ vserverNodeGetInfo,
++ NULL, /* getCapabilties */
++ vserverListDomains,
++ vserverNumOfDomains,
++ vserverDomainCreateLinux,
++ vserverDomainLookupByID,
++ vserverDomainLookupByUUID,
++ vserverDomainLookupByName,
++ vserverDomainSuspend,
++ vserverDomainResume,
++ vserverDomainShutdown,
++ vserverDomainReboot,
++ vserverDomainDestroy,
++ vserverDomainGetOSType,
++ vserverDomainGetMaxMemory,
++ vserverDomainSetMaxMemory,
++ NULL, /* domainSetMemory */
++ vserverDomainGetInfo,
++ NULL, /* domainSave */
++ NULL, /* domainRestore */
++ NULL, /* domainCoreDump */
++ NULL, /* domainSetVcpus */
++ NULL, /* domainPinVcpu */
++ NULL, /* domainGetVcpus */
++ NULL, /* domainGetMaxVcpus */
++ vserverDomainDumpXML,
++ vserverListDefinedDomains,
++ vserverNumOfDefinedDomains,
++ vserverDomainCreate,
++ vserverDomainDefineXML,
++ vserverDomainUndefine,
++ vserverDomainAttachDevice,
++ vserverDomainDetachDevice,
++ vserverDomainGetAutostart,
++ vserverDomainSetAutostart,
++ vserverDomainGetSchedulerType,
++ vserverDomainGetSchedulerParams,
++ vserverDomainSetSchedulerParams,
++ NULL, /* domainMigratePrepare */
++ NULL, /* domainMigratePerform */
++ NULL, /* domainMigrateFinish */
++ NULL, /* domainBlockStats */
++ NULL, /* domainInterfaceStats */
++ NULL, /* nodeGetCellsFreeMemory */
++ NULL, /* getFreeMemory */
++};
++
++int vserverRegister(void)
++{
++ if (virRegisterDriver(&vserverDriver) < 0)
++ return -1;
++ return 0;
++}
++
++#endif
+--- libvirt-0.4.0.orig/src/vserver/vserver_driver.h 1970-01-01 01:00:00.000000000 +0100
++++ libvirt-0.4.0.vserver/src/vserver/vserver_driver.h 2008-01-09 19:14:08.000000000 +0100
+@@ -0,0 +1,137 @@
++/*
++ * Core driver for managing Linux-VServer guests
++ *
++ * Copyright (C) 2007 Daniel Hokka Zakrisson
++ *
++ * 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 Hokka Zakrisson <daniel hozac com>
++ */
++
++#ifdef WITH_VSERVER
++
++/* Kind of a hack */
++#ifdef IN_VSERVER
++#ifndef HAVE_XID_T
++typedef unsigned int xid_t;
++#endif
++#ifndef HAVE_NID_T
++typedef unsigned int nid_t;
++#endif
++#ifndef HAVE_TAG_T
++typedef unsigned int tag_t;
++#endif
++#include <vserver.h>
++
++#define VSERVER_NAME_MAX 64
++#define VSERVER_UTS_MAX 255
++
++enum vserver_initstyle {
++ VSERVER_INIT_NONE,
++ VSERVER_INIT_SYSV,
++ VSERVER_INIT_PLAIN,
++ VSERVER_INIT_GENTOO,
++ VSERVER_INIT_MINIT,
++};
++
++struct vserver_ip {
++ char interface[IFNAMSIZ+1];
++ struct vc_net_addr addr;
++ struct vserver_ip *next;
++};
++
++enum fstab_flags {
++ VSERVER_FSTAB_SHOW=1,
++ VSERVER_FSTAB_OUTPUT=2,
++};
++struct vserver_fstab {
++ char *source;
++ const char *source_type;
++ char *target;
++ char *fstype;
++ char *options;
++ char *rest;
++ int flags;
++ struct vserver_fstab *next;
++};
++
++struct vserver_guest {
++ xid_t xid;
++ char name[VSERVER_NAME_MAX];
++ unsigned char uuid[VIR_UUID_BUFLEN];
++ char *path;
++
++ struct {
++ char hostname[VSERVER_UTS_MAX];
++ char machine[VSERVER_UTS_MAX];
++ char release[VSERVER_UTS_MAX];
++ char version[VSERVER_UTS_MAX];
++ } uts;
++
++ struct vserver_ip *ips;
++
++ struct vc_set_sched sched;
++ unsigned long rss_hard;
++
++ char autostart;
++ enum vserver_initstyle initstyle;
++
++ int status;
++
++ struct vserver_fstab *fstab;
++
++ struct vserver_guest *next;
++};
++
++struct vserver_driver {
++ struct vserver_guest *guests;
++ xmlChar *uri;
++ unsigned int active_guests;
++ unsigned int inactive_guests;
++ unsigned int initialized : 1;
++};
++
++
++#define list_add_tail(list, elem) \
++ do { \
++ __typeof__(list) iter; \
++ if (list) { \
++ for (iter = list; iter->next; iter = iter->next) \
++ ; \
++ iter->next = elem; \
++ } \
++ else \
++ list = elem; \
++ } while (0)
++
++static inline int
++vserverIsRunning(struct vserver_guest *guest) {
++ if (guest->status == VIR_DOMAIN_RUNNING || guest->status == VIR_DOMAIN_PAUSED)
++ return 1;
++ else
++ return 0;
++}
++
++
++int vserverContextIsRunning(const char *path);
++int vserverRunCommand(int do_daemon, const char *cmd, ...);
++void vserverError(virConnectPtr con, virDomainPtr dom, virNetworkPtr net,
++ virErrorNumber error, const char *info);
++#endif
++
++
++extern int vserverRegister(void);
++
++#endif