virt/
domain.rs

1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library.  If not, see
14 * <https://www.gnu.org/licenses/>.
15 *
16 * Sahid Orentino Ferdjaoui <sahid.ferdjaoui@redhat.com>
17 */
18
19use std::ffi::CString;
20use std::{mem, ptr, str};
21
22use uuid::Uuid;
23
24use crate::connect::Connect;
25use crate::domain_snapshot::DomainSnapshot;
26use crate::error::Error;
27use crate::stream::Stream;
28use crate::typedparams::{from_params, to_params};
29use crate::util::c_ulong_to_u64;
30use crate::{param_field_in, param_field_out};
31
32#[derive(Clone, Debug)]
33pub struct DomainInfo {
34    /// The running state, one of virDomainState.
35    pub state: sys::virDomainState,
36    /// The maximum memory in KBytes allowed.
37    pub max_mem: u64,
38    /// The memory in KBytes used by the domain.
39    pub memory: u64,
40    /// The number of virtual CPUs for the domain.
41    pub nr_virt_cpu: u32,
42    /// The CPU time used in nanoseconds.
43    pub cpu_time: u64,
44}
45
46impl DomainInfo {
47    /// # Safety
48    ///
49    /// The caller must ensure that the pointer is valid.
50    pub unsafe fn from_ptr(ptr: sys::virDomainInfoPtr) -> DomainInfo {
51        DomainInfo {
52            state: (*ptr).state as sys::virDomainState,
53            max_mem: c_ulong_to_u64((*ptr).maxMem),
54            memory: c_ulong_to_u64((*ptr).memory),
55            nr_virt_cpu: (*ptr).nrVirtCpu as u32,
56            cpu_time: (*ptr).cpuTime,
57        }
58    }
59}
60
61#[derive(Clone, Debug)]
62pub struct BlockStats {
63    /// Number of read requests
64    pub rd_req: i64,
65    /// Number of read bytes
66    pub rd_bytes: i64,
67    /// Number of write requests
68    pub wr_req: i64,
69    /// Number of write bytes
70    pub wr_bytes: i64,
71    /// Xen specific oo_req
72    pub errs: i64,
73}
74
75impl BlockStats {
76    /// # Safety
77    ///
78    /// The caller must ensure that the pointer is valid.
79    pub unsafe fn from_ptr(ptr: sys::virDomainBlockStatsPtr) -> BlockStats {
80        BlockStats {
81            rd_req: (*ptr).rd_req,
82            rd_bytes: (*ptr).rd_bytes,
83            wr_req: (*ptr).wr_req,
84            wr_bytes: (*ptr).wr_bytes,
85            errs: (*ptr).errs,
86        }
87    }
88}
89
90pub struct DomainStatsRecord {
91    // TODO(sahid): needs to be implemented
92    pub ptr: sys::virDomainStatsRecordPtr,
93}
94
95#[derive(Clone, Debug)]
96pub struct BlockInfo {
97    /// Logical size in bytes of the image (how much storage the guest
98    /// will see).
99    pub capacity: u64,
100    /// Host storage in bytes occupied by the image (such as highest
101    /// allocated extent if there are no holes, similar to 'du').
102    pub allocation: u64,
103    /// Host physical size in bytes of the image container (last
104    /// offset, similar to 'ls')
105    pub physical: u64,
106}
107
108impl BlockInfo {
109    /// # Safety
110    ///
111    /// The caller must ensure that the pointer is valid.
112    pub unsafe fn from_ptr(ptr: sys::virDomainBlockInfoPtr) -> BlockInfo {
113        BlockInfo {
114            capacity: (*ptr).capacity,
115            allocation: (*ptr).allocation,
116            physical: (*ptr).physical,
117        }
118    }
119}
120
121#[derive(Clone, Debug, Default)]
122pub struct MemoryParameters {
123    /// Represents the maximum memory the guest can use.
124    pub hard_limit: Option<u64>,
125    /// Represents the memory upper limit enforced during memory
126    /// contention.
127    pub soft_limit: Option<u64>,
128    /// Represents the minimum memory guaranteed to be reserved for
129    /// the guest.
130    pub min_guarantee: Option<u64>,
131    /// Represents the maximum swap plus memory the guest can use.
132    pub swap_hard_limit: Option<u64>,
133}
134
135macro_rules! memory_parameters_fields {
136    ($dir:ident, $var:ident) => {
137        vec![
138            $dir!(sys::VIR_DOMAIN_MEMORY_HARD_LIMIT, UInt64, $var.hard_limit),
139            $dir!(sys::VIR_DOMAIN_MEMORY_SOFT_LIMIT, UInt64, $var.soft_limit),
140            $dir!(
141                sys::VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
142                UInt64,
143                $var.min_guarantee
144            ),
145            $dir!(
146                sys::VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
147                UInt64,
148                $var.swap_hard_limit
149            ),
150        ]
151    };
152}
153
154impl MemoryParameters {
155    pub const VALUE_UNLIMITED: u64 = sys::VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
156
157    pub fn from_vec(vec: Vec<sys::virTypedParameter>) -> MemoryParameters {
158        let mut ret = MemoryParameters::default();
159        let fields = memory_parameters_fields!(param_field_in, ret);
160        from_params(vec, fields);
161        ret
162    }
163
164    pub fn to_vec(&self) -> Vec<sys::virTypedParameter> {
165        let fields = memory_parameters_fields!(param_field_out, self);
166        to_params(fields)
167    }
168}
169
170macro_rules! numa_parameters_fields {
171    ($dir:ident, $var:ident) => {
172        vec![
173            $dir!(sys::VIR_DOMAIN_NUMA_NODESET, String, $var.node_set),
174            $dir!(sys::VIR_DOMAIN_NUMA_MODE, Int32, $var.mode),
175        ]
176    };
177}
178
179#[derive(Clone, Debug, Default)]
180pub struct NUMAParameters {
181    /// Lists the numa nodeset of a domain.
182    pub node_set: Option<String>,
183    /// Numa mode of a domain, as an int containing a
184    /// DomainNumatuneMemMode value.
185    pub mode: Option<i32>,
186}
187
188impl NUMAParameters {
189    pub fn from_vec(vec: Vec<sys::virTypedParameter>) -> NUMAParameters {
190        let mut ret = NUMAParameters::default();
191        let fields = numa_parameters_fields!(param_field_in, ret);
192        from_params(vec, fields);
193        ret
194    }
195
196    pub fn to_vec(&self) -> Vec<sys::virTypedParameter> {
197        let fields = numa_parameters_fields!(param_field_out, self);
198        to_params(fields)
199    }
200}
201
202macro_rules! migrate_parameters_fields {
203    ($dir:ident, $var:ident) => {
204        vec![
205            $dir!(
206                sys::VIR_MIGRATE_PARAM_AUTO_CONVERGE_INCREMENT,
207                Int32,
208                $var.auto_converge_increment
209            ),
210            $dir!(
211                sys::VIR_MIGRATE_PARAM_AUTO_CONVERGE_INITIAL,
212                Int32,
213                $var.auto_converge_initial
214            ),
215            $dir!(sys::VIR_MIGRATE_PARAM_BANDWIDTH, UInt64, $var.bandwidth),
216            $dir!(
217                sys::VIR_MIGRATE_PARAM_BANDWIDTH_POSTCOPY,
218                UInt64,
219                $var.bandwidth_postcopy
220            ),
221            $dir!(sys::VIR_MIGRATE_PARAM_COMPRESSION, String, $var.compression),
222            $dir!(
223                sys::VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS,
224                Int32,
225                $var.compression_mt_dthreads
226            ),
227            $dir!(
228                sys::VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL,
229                Int32,
230                $var.compression_mt_level
231            ),
232            $dir!(
233                sys::VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS,
234                Int32,
235                $var.compression_mt_threads
236            ),
237            $dir!(
238                sys::VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE,
239                UInt64,
240                $var.compression_xbzrle_cache
241            ),
242            $dir!(
243                sys::VIR_MIGRATE_PARAM_COMPRESSION_ZLIB_LEVEL,
244                Int32,
245                $var.compression_zlib_level
246            ),
247            $dir!(
248                sys::VIR_MIGRATE_PARAM_COMPRESSION_ZSTD_LEVEL,
249                Int32,
250                $var.compression_zstd_level
251            ),
252            $dir!(sys::VIR_MIGRATE_PARAM_DEST_NAME, String, $var.dest_name),
253            $dir!(sys::VIR_MIGRATE_PARAM_DEST_XML, String, $var.dest_xml),
254            $dir!(sys::VIR_MIGRATE_PARAM_DISKS_PORT, Int32, $var.disks_port),
255            $dir!(sys::VIR_MIGRATE_PARAM_DISKS_URI, String, $var.disks_uri),
256            $dir!(
257                sys::VIR_MIGRATE_PARAM_GRAPHICS_URI,
258                String,
259                $var.graphics_uri
260            ),
261            $dir!(
262                sys::VIR_MIGRATE_PARAM_LISTEN_ADDRESS,
263                String,
264                $var.listen_address
265            ),
266            $dir!(
267                sys::VIR_MIGRATE_PARAM_MIGRATE_DISKS,
268                VecString,
269                $var.migrate_disks
270            ),
271            $dir!(
272                sys::VIR_MIGRATE_PARAM_PARALLEL_CONNECTIONS,
273                Int32,
274                $var.parallel_connections
275            ),
276            $dir!(sys::VIR_MIGRATE_PARAM_PERSIST_XML, String, $var.persist_xml),
277            $dir!(
278                sys::VIR_MIGRATE_PARAM_TLS_DESTINATION,
279                String,
280                $var.tls_destination
281            ),
282            $dir!(sys::VIR_MIGRATE_PARAM_URI, String, $var.uri),
283        ]
284    };
285}
286
287#[derive(Clone, Debug, Default)]
288pub struct MigrateParameters {
289    pub auto_converge_increment: Option<i32>,
290    pub auto_converge_initial: Option<i32>,
291    pub bandwidth: Option<u64>,
292    pub bandwidth_postcopy: Option<u64>,
293    pub compression: Option<String>,
294    pub compression_mt_dthreads: Option<i32>,
295    pub compression_mt_level: Option<i32>,
296    pub compression_mt_threads: Option<i32>,
297    pub compression_xbzrle_cache: Option<u64>,
298    pub compression_zlib_level: Option<i32>,
299    pub compression_zstd_level: Option<i32>,
300    pub dest_name: Option<String>,
301    pub dest_xml: Option<String>,
302    pub disks_port: Option<i32>,
303    pub disks_uri: Option<String>,
304    pub graphics_uri: Option<String>,
305    pub listen_address: Option<String>,
306    pub migrate_disks: Vec<String>,
307    pub parallel_connections: Option<i32>,
308    pub persist_xml: Option<String>,
309    pub tls_destination: Option<String>,
310    pub uri: Option<String>,
311}
312
313impl MigrateParameters {
314    pub fn from_vec(vec: Vec<sys::virTypedParameter>) -> MigrateParameters {
315        let mut ret = MigrateParameters::default();
316        let fields = migrate_parameters_fields!(param_field_in, ret);
317        from_params(vec, fields);
318        ret
319    }
320
321    pub fn to_vec(&self) -> Vec<sys::virTypedParameter> {
322        let fields = migrate_parameters_fields!(param_field_out, self);
323        to_params(fields)
324    }
325}
326
327#[derive(Clone, Debug)]
328pub struct IPAddress {
329    pub typed: i64,
330    pub addr: String,
331    pub prefix: u64,
332}
333
334impl IPAddress {
335    /// # Safety
336    ///
337    /// The caller must ensure that the pointer is valid.
338    pub unsafe fn from_ptr(ptr: sys::virDomainIPAddressPtr) -> IPAddress {
339        IPAddress {
340            typed: (*ptr).type_ as i64,
341            addr: c_chars_to_string!((*ptr).addr),
342            prefix: (*ptr).prefix as u64,
343        }
344    }
345}
346
347#[derive(Clone, Debug)]
348pub struct Interface {
349    pub name: String,
350    pub hwaddr: String,
351    pub naddrs: u64,
352    pub addrs: Vec<IPAddress>,
353}
354
355impl Interface {
356    /// # Safety
357    ///
358    /// The caller must ensure that the pointer is valid.
359    pub unsafe fn from_ptr(ptr: sys::virDomainInterfacePtr) -> Interface {
360        let naddrs = (*ptr).naddrs;
361        let mut addrs = vec![];
362        for x in 0..naddrs as isize {
363            addrs.push(IPAddress::from_ptr((*ptr).addrs.offset(x)));
364        }
365        Interface {
366            name: c_chars_to_string!((*ptr).name),
367            hwaddr: c_chars_to_string!((*ptr).hwaddr),
368            naddrs: naddrs as u64,
369            addrs,
370        }
371    }
372}
373
374#[derive(Clone, Debug)]
375pub struct InterfaceStats {
376    pub rx_bytes: i64,
377    pub rx_packets: i64,
378    pub rx_errs: i64,
379    pub rx_drop: i64,
380    pub tx_bytes: i64,
381    pub tx_packets: i64,
382    pub tx_errs: i64,
383    pub tx_drop: i64,
384}
385
386impl InterfaceStats {
387    /// # Safety
388    ///
389    /// The caller must ensure that the pointer is valid.
390    pub unsafe fn from_ptr(ptr: sys::virDomainInterfaceStatsPtr) -> InterfaceStats {
391        InterfaceStats {
392            rx_bytes: (*ptr).rx_bytes,
393            rx_packets: (*ptr).rx_packets,
394            rx_errs: (*ptr).rx_errs,
395            rx_drop: (*ptr).rx_drop,
396            tx_bytes: (*ptr).tx_bytes,
397            tx_packets: (*ptr).tx_packets,
398            tx_errs: (*ptr).tx_errs,
399            tx_drop: (*ptr).tx_drop,
400        }
401    }
402}
403
404#[derive(Clone, Debug)]
405pub struct MemoryStat {
406    pub tag: u32,
407    pub val: u64,
408}
409
410impl MemoryStat {
411    /// # Safety
412    ///
413    /// The caller must ensure that the pointer is valid.
414    pub unsafe fn from_ptr(ptr: *const sys::virDomainMemoryStatStruct) -> MemoryStat {
415        MemoryStat {
416            tag: (*ptr).tag as u32,
417            val: (*ptr).val,
418        }
419    }
420}
421
422/// Information about the progress of a background job that is
423/// affecting a domain.
424#[derive(Clone, Debug, Default)]
425pub struct JobStats {
426    pub r#type: i32,
427
428    pub auto_converge_throttle: Option<i32>,
429
430    pub compression_bytes: Option<u64>,
431    pub compression_cache: Option<u64>,
432    pub compression_cache_misses: Option<u64>,
433    pub compression_overflow: Option<u64>,
434    pub compression_pages: Option<u64>,
435
436    pub data_processed: Option<u64>,
437    pub data_remaining: Option<u64>,
438    pub data_total: Option<u64>,
439
440    pub disk_bps: Option<u64>,
441    pub disk_processed: Option<u64>,
442    pub disk_remaining: Option<u64>,
443    pub disk_temp_total: Option<u64>,
444    pub disk_temp_used: Option<u64>,
445    pub disk_total: Option<u64>,
446
447    pub downtime: Option<u64>,
448    pub downtime_net: Option<u64>,
449
450    pub error_message: Option<String>,
451
452    pub mem_bps: Option<u64>,
453    pub mem_constant: Option<u64>,
454    pub mem_dirty_rate: Option<u64>,
455    pub mem_iteration: Option<u64>,
456    pub mem_normal: Option<u64>,
457    pub mem_normal_bytes: Option<u64>,
458    pub mem_page_size: Option<u64>,
459    pub mem_postcopy_reqs: Option<u64>,
460    pub mem_processed: Option<u64>,
461    pub mem_remaining: Option<u64>,
462    pub mem_total: Option<u64>,
463
464    pub operation: Option<i32>,
465
466    pub setup_time: Option<u64>,
467
468    pub success: Option<bool>,
469
470    pub time_elapsed: Option<u64>,
471    pub time_elapsed_net: Option<u64>,
472    pub time_remaining: Option<u64>,
473}
474
475macro_rules! job_stats_fields {
476    ($dir:ident, $var:ident) => {
477        vec![
478            $dir!(
479                sys::VIR_DOMAIN_JOB_AUTO_CONVERGE_THROTTLE,
480                Int32,
481                $var.auto_converge_throttle
482            ),
483            $dir!(
484                sys::VIR_DOMAIN_JOB_COMPRESSION_BYTES,
485                UInt64,
486                $var.compression_bytes
487            ),
488            $dir!(
489                sys::VIR_DOMAIN_JOB_COMPRESSION_CACHE,
490                UInt64,
491                $var.compression_cache
492            ),
493            $dir!(
494                sys::VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES,
495                UInt64,
496                $var.compression_cache_misses
497            ),
498            $dir!(
499                sys::VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW,
500                UInt64,
501                $var.compression_overflow
502            ),
503            $dir!(
504                sys::VIR_DOMAIN_JOB_COMPRESSION_PAGES,
505                UInt64,
506                $var.compression_pages
507            ),
508            $dir!(
509                sys::VIR_DOMAIN_JOB_DATA_PROCESSED,
510                UInt64,
511                $var.data_processed
512            ),
513            $dir!(
514                sys::VIR_DOMAIN_JOB_DATA_REMAINING,
515                UInt64,
516                $var.data_remaining
517            ),
518            $dir!(sys::VIR_DOMAIN_JOB_DATA_TOTAL, UInt64, $var.data_total),
519            $dir!(sys::VIR_DOMAIN_JOB_DISK_BPS, UInt64, $var.disk_bps),
520            $dir!(
521                sys::VIR_DOMAIN_JOB_DISK_PROCESSED,
522                UInt64,
523                $var.disk_processed
524            ),
525            $dir!(
526                sys::VIR_DOMAIN_JOB_DISK_REMAINING,
527                UInt64,
528                $var.disk_remaining
529            ),
530            $dir!(
531                sys::VIR_DOMAIN_JOB_DISK_TEMP_TOTAL,
532                UInt64,
533                $var.disk_temp_total
534            ),
535            $dir!(
536                sys::VIR_DOMAIN_JOB_DISK_TEMP_USED,
537                UInt64,
538                $var.disk_temp_used
539            ),
540            $dir!(sys::VIR_DOMAIN_JOB_DISK_TOTAL, UInt64, $var.disk_total),
541            $dir!(sys::VIR_DOMAIN_JOB_DOWNTIME, UInt64, $var.downtime),
542            $dir!(sys::VIR_DOMAIN_JOB_DOWNTIME_NET, UInt64, $var.downtime_net),
543            $dir!(sys::VIR_DOMAIN_JOB_ERRMSG, String, $var.error_message),
544            $dir!(sys::VIR_DOMAIN_JOB_MEMORY_BPS, UInt64, $var.mem_bps),
545            $dir!(
546                sys::VIR_DOMAIN_JOB_MEMORY_CONSTANT,
547                UInt64,
548                $var.mem_constant
549            ),
550            $dir!(
551                sys::VIR_DOMAIN_JOB_MEMORY_DIRTY_RATE,
552                UInt64,
553                $var.mem_dirty_rate
554            ),
555            $dir!(
556                sys::VIR_DOMAIN_JOB_MEMORY_ITERATION,
557                UInt64,
558                $var.mem_iteration
559            ),
560            $dir!(sys::VIR_DOMAIN_JOB_MEMORY_NORMAL, UInt64, $var.mem_normal),
561            $dir!(
562                sys::VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES,
563                UInt64,
564                $var.mem_normal_bytes
565            ),
566            $dir!(
567                sys::VIR_DOMAIN_JOB_MEMORY_PAGE_SIZE,
568                UInt64,
569                $var.mem_page_size
570            ),
571            $dir!(
572                sys::VIR_DOMAIN_JOB_MEMORY_POSTCOPY_REQS,
573                UInt64,
574                $var.mem_postcopy_reqs
575            ),
576            $dir!(
577                sys::VIR_DOMAIN_JOB_MEMORY_PROCESSED,
578                UInt64,
579                $var.mem_processed
580            ),
581            $dir!(
582                sys::VIR_DOMAIN_JOB_MEMORY_REMAINING,
583                UInt64,
584                $var.mem_remaining
585            ),
586            $dir!(sys::VIR_DOMAIN_JOB_MEMORY_TOTAL, UInt64, $var.mem_total),
587            $dir!(sys::VIR_DOMAIN_JOB_OPERATION, Int32, $var.operation),
588            $dir!(sys::VIR_DOMAIN_JOB_SETUP_TIME, UInt64, $var.setup_time),
589            $dir!(sys::VIR_DOMAIN_JOB_SUCCESS, Bool, $var.success),
590            $dir!(sys::VIR_DOMAIN_JOB_TIME_ELAPSED, UInt64, $var.time_elapsed),
591            $dir!(
592                sys::VIR_DOMAIN_JOB_TIME_ELAPSED_NET,
593                UInt64,
594                $var.time_elapsed_net
595            ),
596            $dir!(
597                sys::VIR_DOMAIN_JOB_TIME_REMAINING,
598                UInt64,
599                $var.time_remaining
600            ),
601        ]
602    };
603}
604
605impl From<(i32, Vec<sys::virTypedParameter>)> for JobStats {
606    fn from((r#type, params): (i32, Vec<sys::virTypedParameter>)) -> Self {
607        let mut stats = Self {
608            r#type,
609            ..Default::default()
610        };
611
612        let fields = job_stats_fields!(param_field_in, stats);
613
614        from_params(params, fields);
615
616        stats
617    }
618}
619
620/// Structure representing the CFS scheduler cpu bandwidth parameters
621/// see <https://www.kernel.org/doc/html/latest/scheduler/sched-bwc.html>
622#[derive(Clone, Debug, Default)]
623pub struct SchedBandwidth {
624    pub period: Option<u64>,
625    pub quota: Option<i64>,
626}
627
628#[derive(Clone, Debug, Default)]
629pub struct SchedulerInfo {
630    pub scheduler_type: String,
631    // cpu shares for the domain.
632    pub cpu_shares: Option<u64>,
633    // Bandwidth allocated for the vcpu threads.
634    pub vcpu_bw: SchedBandwidth,
635    // Bandwidth allocated for the emulator threads.
636    pub emulator_bw: SchedBandwidth,
637    // Bandwidth allocated for the Domain.
638    pub global_bw: SchedBandwidth,
639    // Bandwidth allocated for the io threads..
640    pub iothread_bw: SchedBandwidth,
641    // Credit scheduler relative weight
642    pub weight: Option<u32>,
643    // Credit scheduler cap
644    pub cap: Option<u32>,
645    // Allocation scheduler reservation
646    pub reservation: Option<i64>,
647    // Allocation scheduler limit
648    pub limit: Option<i64>,
649    // Allocation scheduler shares
650    pub shares: Option<i32>,
651}
652
653macro_rules! scheduler_info_fields {
654    ($dir:ident, $var:ident) => {
655        vec![
656            $dir!(
657                sys::VIR_DOMAIN_SCHEDULER_CPU_SHARES,
658                UInt64,
659                $var.cpu_shares
660            ),
661            $dir!(
662                sys::VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
663                UInt64,
664                $var.vcpu_bw.period
665            ),
666            $dir!(
667                sys::VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
668                Int64,
669                $var.vcpu_bw.quota
670            ),
671            $dir!(
672                sys::VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD,
673                UInt64,
674                $var.emulator_bw.period
675            ),
676            $dir!(
677                sys::VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA,
678                Int64,
679                $var.emulator_bw.quota
680            ),
681            $dir!(
682                sys::VIR_DOMAIN_SCHEDULER_GLOBAL_PERIOD,
683                UInt64,
684                $var.global_bw.period
685            ),
686            $dir!(
687                sys::VIR_DOMAIN_SCHEDULER_GLOBAL_QUOTA,
688                Int64,
689                $var.global_bw.quota
690            ),
691            $dir!(
692                sys::VIR_DOMAIN_SCHEDULER_IOTHREAD_PERIOD,
693                UInt64,
694                $var.iothread_bw.period
695            ),
696            $dir!(
697                sys::VIR_DOMAIN_SCHEDULER_IOTHREAD_QUOTA,
698                Int64,
699                $var.iothread_bw.quota
700            ),
701            $dir!(sys::VIR_DOMAIN_SCHEDULER_WEIGHT, UInt32, $var.weight),
702            $dir!(sys::VIR_DOMAIN_SCHEDULER_CAP, UInt32, $var.cap),
703            $dir!(
704                sys::VIR_DOMAIN_SCHEDULER_RESERVATION,
705                Int64,
706                $var.reservation
707            ),
708            $dir!(sys::VIR_DOMAIN_SCHEDULER_LIMIT, Int64, $var.limit),
709            $dir!(sys::VIR_DOMAIN_SCHEDULER_SHARES, Int32, $var.shares),
710        ]
711    };
712}
713
714impl SchedulerInfo {
715    pub fn from_vec(vec: Vec<sys::virTypedParameter>, scheduler_type: String) -> SchedulerInfo {
716        let mut ret = SchedulerInfo {
717            scheduler_type,
718            ..Default::default()
719        };
720        let fields = scheduler_info_fields!(param_field_in, ret);
721        from_params(vec, fields);
722        ret
723    }
724
725    pub fn to_vec(&self) -> Vec<sys::virTypedParameter> {
726        let fields = scheduler_info_fields!(param_field_out, self);
727        to_params(fields)
728    }
729}
730
731/// Provides APIs for the management of domains.
732///
733/// See <https://libvirt.org/html/libvirt-libvirt-domain.html>
734#[derive(Debug)]
735pub struct Domain {
736    ptr: Option<sys::virDomainPtr>,
737}
738
739unsafe impl Send for Domain {}
740unsafe impl Sync for Domain {}
741
742impl Drop for Domain {
743    fn drop(&mut self) {
744        if self.ptr.is_some() {
745            if let Err(e) = self.free() {
746                panic!("Unable to drop memory for Domain: {e}")
747            }
748        }
749    }
750}
751
752impl Clone for Domain {
753    /// Creates a copy of a domain.
754    ///
755    /// Increments the internal reference counter on the given
756    /// domain. For each call to this method, there shall be a
757    /// corresponding call to [`free()`].
758    ///
759    /// [`free()`]: Domain::free
760    fn clone(&self) -> Self {
761        self.add_ref().unwrap()
762    }
763}
764
765impl Domain {
766    /// # Safety
767    ///
768    /// The caller must ensure that the pointer is valid.
769    pub unsafe fn from_ptr(ptr: sys::virDomainPtr) -> Domain {
770        Domain { ptr: Some(ptr) }
771    }
772
773    fn add_ref(&self) -> Result<Domain, Error> {
774        unsafe {
775            if sys::virDomainRef(self.as_ptr()) == -1 {
776                return Err(Error::last_error());
777            }
778        }
779
780        Ok(unsafe { Domain::from_ptr(self.as_ptr()) })
781    }
782
783    pub fn as_ptr(&self) -> sys::virDomainPtr {
784        self.ptr.unwrap()
785    }
786
787    pub fn get_connect(&self) -> Result<Connect, Error> {
788        let ptr = unsafe { sys::virDomainGetConnect(self.as_ptr()) };
789        if ptr.is_null() {
790            return Err(Error::last_error());
791        }
792        Ok(unsafe { Connect::from_ptr(ptr) })
793    }
794
795    pub fn lookup_by_id(conn: &Connect, id: u32) -> Result<Domain, Error> {
796        let ptr = unsafe { sys::virDomainLookupByID(conn.as_ptr(), id as libc::c_int) };
797        if ptr.is_null() {
798            return Err(Error::last_error());
799        }
800        Ok(unsafe { Domain::from_ptr(ptr) })
801    }
802
803    pub fn lookup_by_name(conn: &Connect, id: &str) -> Result<Domain, Error> {
804        let id_buf = CString::new(id).unwrap();
805        let ptr = unsafe { sys::virDomainLookupByName(conn.as_ptr(), id_buf.as_ptr()) };
806        if ptr.is_null() {
807            return Err(Error::last_error());
808        }
809        Ok(unsafe { Domain::from_ptr(ptr) })
810    }
811
812    pub fn lookup_by_uuid(conn: &Connect, uuid: Uuid) -> Result<Domain, Error> {
813        let ptr = unsafe { sys::virDomainLookupByUUID(conn.as_ptr(), uuid.as_bytes().as_ptr()) };
814        if ptr.is_null() {
815            return Err(Error::last_error());
816        }
817        Ok(unsafe { Domain::from_ptr(ptr) })
818    }
819
820    pub fn lookup_by_uuid_string(conn: &Connect, uuid: &str) -> Result<Domain, Error> {
821        let uuid_buf = CString::new(uuid).unwrap();
822        let ptr = unsafe { sys::virDomainLookupByUUIDString(conn.as_ptr(), uuid_buf.as_ptr()) };
823        if ptr.is_null() {
824            return Err(Error::last_error());
825        }
826        Ok(unsafe { Domain::from_ptr(ptr) })
827    }
828
829    /// Extracts domain state.
830    ///
831    /// Each state can be accompanied with a reason (if known) which
832    /// led to the state.
833    pub fn get_state(&self) -> Result<(sys::virDomainState, i32), Error> {
834        let mut state: libc::c_int = -1;
835        let mut reason: libc::c_int = -1;
836        let ret = unsafe { sys::virDomainGetState(self.as_ptr(), &mut state, &mut reason, 0) };
837        if ret == -1 {
838            return Err(Error::last_error());
839        }
840        Ok((state as sys::virDomainState, reason))
841    }
842
843    /// Get the public name of the domain.
844    pub fn get_name(&self) -> Result<String, Error> {
845        let n = unsafe { sys::virDomainGetName(self.as_ptr()) };
846        if n.is_null() {
847            return Err(Error::last_error());
848        }
849        Ok(unsafe { c_chars_to_string!(n, nofree) })
850    }
851
852    /// Get the type of domain operating system.
853    pub fn get_os_type(&self) -> Result<String, Error> {
854        let n = unsafe { sys::virDomainGetOSType(self.as_ptr()) };
855        if n.is_null() {
856            return Err(Error::last_error());
857        }
858        Ok(unsafe { c_chars_to_string!(n) })
859    }
860
861    /// Get the hostname for that domain.
862    pub fn get_hostname(&self, flags: u32) -> Result<String, Error> {
863        let n = unsafe { sys::virDomainGetHostname(self.as_ptr(), flags as libc::c_uint) };
864        if n.is_null() {
865            return Err(Error::last_error());
866        }
867        Ok(unsafe { c_chars_to_string!(n) })
868    }
869
870    pub fn get_uuid(&self) -> Result<Uuid, Error> {
871        let mut uuid: [libc::c_uchar; sys::VIR_UUID_BUFLEN as usize] =
872            [0; sys::VIR_UUID_BUFLEN as usize];
873        let ret = unsafe { sys::virDomainGetUUID(self.as_ptr(), uuid.as_mut_ptr()) };
874        if ret == -1 {
875            return Err(Error::last_error());
876        }
877        Ok(Uuid::from_bytes(uuid))
878    }
879
880    /// Get the UUID for a domain as string.
881    ///
882    /// For more information about UUID see RFC4122.
883    pub fn get_uuid_string(&self) -> Result<String, Error> {
884        let mut uuid: [libc::c_char; sys::VIR_UUID_STRING_BUFLEN as usize] =
885            [0; sys::VIR_UUID_STRING_BUFLEN as usize];
886        let ret = unsafe { sys::virDomainGetUUIDString(self.as_ptr(), uuid.as_mut_ptr()) };
887        if ret == -1 {
888            return Err(Error::last_error());
889        }
890        Ok(unsafe { c_chars_to_string!(uuid.as_ptr(), nofree) })
891    }
892
893    /// Get the hypervisor ID number for the domain
894    pub fn get_id(&self) -> Option<u32> {
895        let ret = unsafe { sys::virDomainGetID(self.as_ptr()) };
896        if ret as i32 == -1 {
897            return None;
898        }
899        Some(ret)
900    }
901
902    /// Provide an XML description of the domain. The description may
903    /// be reused later to relaunch the domain with [`create_xml()`].
904    ///
905    /// [`create_xml()`]: Domain::create_xml
906    pub fn get_xml_desc(&self, flags: sys::virDomainCreateFlags) -> Result<String, Error> {
907        let xml = unsafe { sys::virDomainGetXMLDesc(self.as_ptr(), flags) };
908        if xml.is_null() {
909            return Err(Error::last_error());
910        }
911        Ok(unsafe { c_chars_to_string!(xml) })
912    }
913
914    /// Launch a defined domain. If the call succeeds the domain moves
915    /// from the defined to the running domains pools. The domain will
916    /// be paused only if restoring from managed state created from a
917    /// paused domain.For more control, see [`create_with_flags()`].
918    ///
919    /// [`create_with_flags()`]: Domain::create_with_flags
920    pub fn create(&self) -> Result<u32, Error> {
921        let ret = unsafe { sys::virDomainCreate(self.as_ptr()) };
922        if ret == -1 {
923            return Err(Error::last_error());
924        }
925        Ok(ret as u32)
926    }
927
928    /// Launch a defined domain. If the call succeeds the domain moves
929    /// from the defined to the running domains pools.
930    pub fn create_with_flags(&self, flags: sys::virDomainCreateFlags) -> Result<u32, Error> {
931        let res = unsafe { sys::virDomainCreateWithFlags(self.as_ptr(), flags as libc::c_uint) };
932        if res == -1 {
933            return Err(Error::last_error());
934        }
935        Ok(res as u32)
936    }
937
938    /// Extract information about a domain. Note that if the
939    /// connection used to get the domain is limited only a partial
940    /// set of the information can be extracted.
941    pub fn get_info(&self) -> Result<DomainInfo, Error> {
942        let mut pinfo = mem::MaybeUninit::uninit();
943        let res = unsafe { sys::virDomainGetInfo(self.as_ptr(), pinfo.as_mut_ptr()) };
944        if res == -1 {
945            return Err(Error::last_error());
946        }
947        Ok(unsafe { DomainInfo::from_ptr(&mut pinfo.assume_init()) })
948    }
949
950    /// Launch a new guest domain, based on an XML description similar
951    /// to the one returned by [`get_xml_desc()`].
952    ///
953    /// This function may require privileged access to the hypervisor.
954    ///
955    /// The domain is not persistent, so its definition will disappear
956    /// when it is destroyed, or if the host is restarted (see
957    /// [`define_xml()`] to define persistent domains).
958    ///
959    /// [`get_xml_desc()`]: Domain::get_xml_desc
960    /// [`define_xml()`]: Domain::define_xml
961    pub fn create_xml(
962        conn: &Connect,
963        xml: &str,
964        flags: sys::virDomainCreateFlags,
965    ) -> Result<Domain, Error> {
966        let xml_buf = CString::new(xml).unwrap();
967        let ptr = unsafe {
968            sys::virDomainCreateXML(conn.as_ptr(), xml_buf.as_ptr(), flags as libc::c_uint)
969        };
970        if ptr.is_null() {
971            return Err(Error::last_error());
972        }
973        Ok(unsafe { Domain::from_ptr(ptr) })
974    }
975
976    /// Define a domain, but does not start it.
977    ///
978    /// This definition is persistent, until explicitly undefined with
979    /// [`undefine()`]. A previous definition for this domain would be
980    /// overridden if it already exists.
981    ///
982    /// # Note:
983    ///
984    /// Some hypervisors may prevent this operation if there is a
985    /// current block copy operation on a transient domain with the
986    /// same id as the domain being defined.
987    ///
988    /// [`undefine()`]: Domain::undefine
989    pub fn define_xml(conn: &Connect, xml: &str) -> Result<Domain, Error> {
990        let xml_buf = CString::new(xml).unwrap();
991        let ptr = unsafe { sys::virDomainDefineXML(conn.as_ptr(), xml_buf.as_ptr()) };
992        if ptr.is_null() {
993            return Err(Error::last_error());
994        }
995        Ok(unsafe { Domain::from_ptr(ptr) })
996    }
997
998    /// Define a domain, but does not start it.
999    ///
1000    /// This definition is persistent, until explicitly undefined with
1001    /// [`undefine()`]. A previous definition for this domain would be
1002    /// overridden if it already exists.
1003    ///
1004    /// # Note:
1005    ///
1006    /// Some hypervisors may prevent this operation if there is a
1007    /// current block copy operation on a transient domain with the
1008    /// same id as the domain being defined.
1009    ///
1010    /// [`undefine()`]: Domain::undefine
1011    pub fn define_xml_flags(
1012        conn: &Connect,
1013        xml: &str,
1014        flags: sys::virDomainDefineFlags,
1015    ) -> Result<Domain, Error> {
1016        let xml_buf = CString::new(xml).unwrap();
1017        let ptr = unsafe {
1018            sys::virDomainDefineXMLFlags(conn.as_ptr(), xml_buf.as_ptr(), flags as libc::c_uint)
1019        };
1020        if ptr.is_null() {
1021            return Err(Error::last_error());
1022        }
1023        Ok(unsafe { Domain::from_ptr(ptr) })
1024    }
1025
1026    /// Destroy the domain. The running instance is shutdown if not
1027    /// down already and all resources used by it are given back to
1028    /// the hypervisor. This does not free the associated virDomainPtr
1029    /// object. This function may require privileged access.
1030    pub fn destroy(&self) -> Result<(), Error> {
1031        let ret = unsafe { sys::virDomainDestroy(self.as_ptr()) };
1032        if ret == -1 {
1033            return Err(Error::last_error());
1034        }
1035        Ok(())
1036    }
1037
1038    /// Reset a domain immediately without any guest OS shutdown.
1039    /// Reset emulates the power reset button on a machine, where all
1040    /// hardware sees the RST line set and reinitializes internal
1041    /// state.
1042    ///
1043    /// Note that there is a risk of data loss caused by reset without
1044    /// any guest OS shutdown.
1045    pub fn reset(&self) -> Result<u32, Error> {
1046        let ret = unsafe { sys::virDomainReset(self.as_ptr(), 0) };
1047        if ret == -1 {
1048            return Err(Error::last_error());
1049        }
1050        Ok(ret as u32)
1051    }
1052
1053    /// Destroy the domain. The running instance is shutdown if not
1054    /// down already and all resources used by it are given back to
1055    /// the hypervisor. This does not free the associated virDomainPtr
1056    /// object. This function may require privileged access.
1057    pub fn destroy_flags(&self, flags: sys::virDomainDestroyFlagsValues) -> Result<u32, Error> {
1058        let ret = unsafe { sys::virDomainDestroyFlags(self.as_ptr(), flags) };
1059        if ret == -1 {
1060            return Err(Error::last_error());
1061        }
1062        Ok(ret as u32)
1063    }
1064
1065    /// Shutdown a domain
1066    ///
1067    /// The domain object is still usable thereafter, but the domain
1068    /// OS is being stopped. Note that the guest OS may ignore the
1069    /// request. Additionally, the hypervisor may check and support
1070    /// the domain 'on_poweroff' XML setting resulting in a domain
1071    /// that reboots instead of shutting down. For guests that react
1072    /// to a shutdown request, the differences from [`destroy()`] are
1073    /// that the guests disk storage will be in a stable state rather
1074    /// than having the (virtual) power cord pulled, and this command
1075    /// returns as soon as the shutdown request is issued rather than
1076    /// blocking until the guest is no longer running.
1077    ///
1078    /// [`destroy()`]: Domain::destroy
1079    pub fn shutdown(&self) -> Result<u32, Error> {
1080        let ret = unsafe { sys::virDomainShutdown(self.as_ptr()) };
1081        if ret == -1 {
1082            return Err(Error::last_error());
1083        }
1084        Ok(ret as u32)
1085    }
1086
1087    /// Shutdown a domain, the domain object is still usable thereafter
1088    /// but the domain OS is being stopped. Note that the guest OS may
1089    /// ignore the request. Additionally, the hypervisor may check and
1090    /// support the domain 'on_poweroff' XML setting resulting in a domain
1091    /// that reboots instead of shutting down. For guests that react to a
1092    /// shutdown request, the differences from [`Domain::destroy()`] are that
1093    /// the guest's disk storage will be in a stable state rather
1094    /// than having the (virtual) power cord pulled, and this command returns
1095    /// as soon as the shutdown request is issued rather than blocking until
1096    /// the guest is no longer running.
1097    ///
1098    /// If the domain is transient and has any snapshot metadata
1099    /// (see virDomainSnapshotNum()), then that metadata will automatically
1100    /// be deleted when the domain quits.
1101    ///
1102    /// If flags is set to zero, then the hypervisor will choose the method of
1103    /// shutdown it considers best. To have greater control pass one or more of
1104    /// the [`sys::virDomainShutdownFlagValues`]. The order in which the hypervisor tries
1105    /// each shutdown method is undefined, and a hypervisor is not required to
1106    /// support all methods.
1107    ///
1108    /// To use guest agent [`sys::VIR_DOMAIN_SHUTDOWN_GUEST_AGENT`] the domain XML must
1109    /// have \<channel\> configured.
1110    pub fn shutdown_flags(&self, flags: sys::virDomainShutdownFlagValues) -> Result<u32, Error> {
1111        let ret = unsafe { sys::virDomainShutdownFlags(self.as_ptr(), flags as libc::c_uint) };
1112        if ret == -1 {
1113            return Err(Error::last_error());
1114        }
1115        Ok(ret as u32)
1116    }
1117
1118    /// Reboot a domain.
1119    ///
1120    /// The domain object is still usable thereafter.
1121    pub fn reboot(&self, flags: sys::virDomainRebootFlagValues) -> Result<(), Error> {
1122        let ret = unsafe { sys::virDomainReboot(self.as_ptr(), flags) };
1123        if ret == -1 {
1124            return Err(Error::last_error());
1125        }
1126        Ok(())
1127    }
1128
1129    /// Suspend a domain.
1130    ///
1131    /// Suspends an active domain, the process is frozen without
1132    /// further access to CPU resources and I/O but the memory used by
1133    /// the domain at the hypervisor level will stay allocated. Use
1134    /// `resume` to reactivate the domain.  This function may
1135    /// require privileged access.  Moreover, suspend may not be
1136    /// supported if domain is in some special state like
1137    /// [`VIR_DOMAIN_PMSUSPENDED`].
1138    ///
1139    /// [`VIR_DOMAIN_PMSUSPENDED`]: sys::VIR_DOMAIN_PMSUSPENDED
1140    pub fn suspend(&self) -> Result<u32, Error> {
1141        let ret = unsafe { sys::virDomainSuspend(self.as_ptr()) };
1142        if ret == -1 {
1143            return Err(Error::last_error());
1144        }
1145        Ok(ret as u32)
1146    }
1147
1148    /// Resume a suspended domain.
1149    ///
1150    /// the process is restarted from the state where it was frozen by
1151    /// calling [`suspend()`]. This function may require privileged
1152    /// access Moreover, resume may not be supported if domain is in
1153    /// some special state like ['VIR_DOMAIN_PMSUSPENDED'].
1154    ///
1155    /// [`suspend()`]: Domain::suspend
1156    /// [`VIR_DOMAIN_PMSUSPENDED`]: sys::VIR_DOMAIN_PMSUSPENDED
1157    pub fn resume(&self) -> Result<u32, Error> {
1158        let ret = unsafe { sys::virDomainResume(self.as_ptr()) };
1159        if ret == -1 {
1160            return Err(Error::last_error());
1161        }
1162        Ok(ret as u32)
1163    }
1164
1165    pub fn pm_wakeup(&self, flags: u32) -> Result<u32, Error> {
1166        let ret = unsafe { sys::virDomainPMWakeup(self.as_ptr(), flags as libc::c_uint) };
1167        if ret == -1 {
1168            return Err(Error::last_error());
1169        }
1170        Ok(ret as u32)
1171    }
1172
1173    /// Determine if the domain is currently running.
1174    pub fn is_active(&self) -> Result<bool, Error> {
1175        let ret = unsafe { sys::virDomainIsActive(self.as_ptr()) };
1176        if ret == -1 {
1177            return Err(Error::last_error());
1178        }
1179        Ok(ret == 1)
1180    }
1181
1182    /// Determine if the domain has a persistent configuration which means it will still exist
1183    /// after shutting down.
1184    pub fn is_persistent(&self) -> Result<bool, Error> {
1185        let ret = unsafe { sys::virDomainIsPersistent(self.as_ptr()) };
1186        if ret == -1 {
1187            return Err(Error::last_error());
1188        }
1189        Ok(ret == 1)
1190    }
1191
1192    /// Undefine a domain.
1193    ///
1194    /// If the domain is running, it's converted to transient domain,
1195    /// without stopping it. If the domain is inactive, the domain
1196    /// configuration is removed.
1197    pub fn undefine(&self) -> Result<(), Error> {
1198        let ret = unsafe { sys::virDomainUndefine(self.as_ptr()) };
1199        if ret == -1 {
1200            return Err(Error::last_error());
1201        }
1202        Ok(())
1203    }
1204
1205    /// Undefine a domain.
1206    ///
1207    /// If the domain is running, it's converted to transient domain,
1208    /// without stopping it. If the domain is inactive, the domain
1209    /// configuration is removed.
1210    pub fn undefine_flags(&self, flags: sys::virDomainUndefineFlagsValues) -> Result<(), Error> {
1211        let ret = unsafe { sys::virDomainUndefineFlags(self.as_ptr(), flags) };
1212        if ret == -1 {
1213            return Err(Error::last_error());
1214        }
1215        Ok(())
1216    }
1217
1218    /// Free the domain object.
1219    ///
1220    /// The running instance is kept alive. The data structure is
1221    /// freed and should not be used thereafter.
1222    pub fn free(&mut self) -> Result<(), Error> {
1223        let ret = unsafe { sys::virDomainFree(self.as_ptr()) };
1224        if ret == -1 {
1225            return Err(Error::last_error());
1226        }
1227        self.ptr = None;
1228        Ok(())
1229    }
1230
1231    pub fn is_updated(&self) -> Result<bool, Error> {
1232        let ret = unsafe { sys::virDomainIsUpdated(self.as_ptr()) };
1233        if ret == -1 {
1234            return Err(Error::last_error());
1235        }
1236        Ok(ret == 1)
1237    }
1238
1239    pub fn get_autostart(&self) -> Result<bool, Error> {
1240        let mut autostart: libc::c_int = 0;
1241        let ret = unsafe { sys::virDomainGetAutostart(self.as_ptr(), &mut autostart) };
1242        if ret == -1 {
1243            return Err(Error::last_error());
1244        }
1245        Ok(autostart == 1)
1246    }
1247
1248    pub fn set_autostart(&self, autostart: bool) -> Result<bool, Error> {
1249        let ret = unsafe { sys::virDomainSetAutostart(self.as_ptr(), autostart as libc::c_int) };
1250        if ret == -1 {
1251            return Err(Error::last_error());
1252        }
1253        Ok(ret == 1)
1254    }
1255
1256    pub fn set_max_memory(&self, memory: u64) -> Result<bool, Error> {
1257        let ret = unsafe { sys::virDomainSetMaxMemory(self.as_ptr(), memory as libc::c_ulong) };
1258        if ret == -1 {
1259            return Err(Error::last_error());
1260        }
1261        Ok(ret == 1)
1262    }
1263
1264    pub fn get_max_memory(&self) -> Result<u64, Error> {
1265        let ret = unsafe { sys::virDomainGetMaxMemory(self.as_ptr()) };
1266        if ret == 0 {
1267            return Err(Error::last_error());
1268        }
1269        Ok(c_ulong_to_u64(ret))
1270    }
1271
1272    pub fn get_max_vcpus(&self) -> Result<u64, Error> {
1273        let ret = unsafe { sys::virDomainGetMaxVcpus(self.as_ptr()) };
1274        if ret == 0 {
1275            return Err(Error::last_error());
1276        }
1277        Ok(ret as u64)
1278    }
1279
1280    pub fn set_memory(&self, memory: u64) -> Result<bool, Error> {
1281        let ret = unsafe { sys::virDomainSetMemory(self.as_ptr(), memory as libc::c_ulong) };
1282        if ret == -1 {
1283            return Err(Error::last_error());
1284        }
1285        Ok(ret == 1)
1286    }
1287
1288    pub fn set_memory_flags(
1289        &self,
1290        memory: u64,
1291        flags: sys::virDomainMemoryModFlags,
1292    ) -> Result<bool, Error> {
1293        let ret = unsafe {
1294            sys::virDomainSetMemoryFlags(
1295                self.as_ptr(),
1296                memory as libc::c_ulong,
1297                flags as libc::c_uint,
1298            )
1299        };
1300        if ret == -1 {
1301            return Err(Error::last_error());
1302        }
1303        Ok(ret == 1)
1304    }
1305
1306    pub fn set_memory_stats_period(
1307        &self,
1308        period: i32,
1309        flags: sys::virDomainMemoryModFlags,
1310    ) -> Result<bool, Error> {
1311        let ret = unsafe {
1312            sys::virDomainSetMemoryStatsPeriod(
1313                self.as_ptr(),
1314                period as libc::c_int,
1315                flags as libc::c_uint,
1316            )
1317        };
1318        if ret == -1 {
1319            return Err(Error::last_error());
1320        }
1321        Ok(ret == 1)
1322    }
1323
1324    pub fn set_vcpus(&self, vcpus: u32) -> Result<bool, Error> {
1325        let ret = unsafe { sys::virDomainSetVcpus(self.as_ptr(), vcpus as libc::c_uint) };
1326        if ret == -1 {
1327            return Err(Error::last_error());
1328        }
1329        Ok(ret == 1)
1330    }
1331
1332    pub fn set_vcpus_flags(
1333        &self,
1334        vcpus: u32,
1335        flags: sys::virDomainVcpuFlags,
1336    ) -> Result<bool, Error> {
1337        let ret = unsafe {
1338            sys::virDomainSetVcpusFlags(self.as_ptr(), vcpus as libc::c_uint, flags as libc::c_uint)
1339        };
1340        if ret == -1 {
1341            return Err(Error::last_error());
1342        }
1343        Ok(ret == 1)
1344    }
1345
1346    pub fn domain_restore(conn: &Connect, path: &str) -> Result<(), Error> {
1347        let path_buf = CString::new(path).unwrap();
1348        let ret = unsafe { sys::virDomainRestore(conn.as_ptr(), path_buf.as_ptr()) };
1349        if ret == -1 {
1350            return Err(Error::last_error());
1351        }
1352        Ok(())
1353    }
1354
1355    pub fn domain_restore_flags(
1356        conn: &Connect,
1357        path: &str,
1358        dxml: Option<&str>,
1359        flags: sys::virDomainSaveRestoreFlags,
1360    ) -> Result<(), Error> {
1361        let path_buf = CString::new(path).unwrap();
1362        let dxml_buf = some_string_to_cstring!(dxml);
1363        let ret = unsafe {
1364            sys::virDomainRestoreFlags(
1365                conn.as_ptr(),
1366                path_buf.as_ptr(),
1367                some_cstring_to_c_chars!(dxml_buf),
1368                flags,
1369            )
1370        };
1371        if ret == -1 {
1372            return Err(Error::last_error());
1373        }
1374        Ok(())
1375    }
1376
1377    pub fn get_vcpus_flags(&self, flags: sys::virDomainVcpuFlags) -> Result<u32, Error> {
1378        let ret = unsafe { sys::virDomainGetVcpusFlags(self.as_ptr(), flags as libc::c_uint) };
1379        if ret == -1 {
1380            return Err(Error::last_error());
1381        }
1382        Ok(ret as u32)
1383    }
1384
1385    pub fn migrate_set_max_speed(&self, bandwidth: u64, flags: u32) -> Result<u32, Error> {
1386        let ret = unsafe {
1387            sys::virDomainMigrateSetMaxSpeed(
1388                self.as_ptr(),
1389                bandwidth as libc::c_ulong,
1390                flags as libc::c_uint,
1391            )
1392        };
1393        if ret == -1 {
1394            return Err(Error::last_error());
1395        }
1396        Ok(ret as u32)
1397    }
1398
1399    pub fn migrate_get_max_speed(&self, flags: u32) -> Result<u64, Error> {
1400        let mut bandwidth: libc::c_ulong = 0;
1401        let ret = unsafe {
1402            sys::virDomainMigrateGetMaxSpeed(self.as_ptr(), &mut bandwidth, flags as libc::c_uint)
1403        };
1404        if ret == -1 {
1405            return Err(Error::last_error());
1406        }
1407        Ok(c_ulong_to_u64(bandwidth))
1408    }
1409
1410    pub fn migrate_set_compression_cache(&self, size: u64, flags: u32) -> Result<u32, Error> {
1411        let ret = unsafe {
1412            sys::virDomainMigrateSetCompressionCache(
1413                self.as_ptr(),
1414                size as libc::c_ulonglong,
1415                flags as libc::c_uint,
1416            )
1417        };
1418        if ret == -1 {
1419            return Err(Error::last_error());
1420        }
1421        Ok(ret as u32)
1422    }
1423
1424    pub fn migrate_get_compression_cache(&self, flags: u32) -> Result<u64, Error> {
1425        let mut size: libc::c_ulonglong = 0;
1426        let ret = unsafe {
1427            sys::virDomainMigrateGetCompressionCache(
1428                self.as_ptr(),
1429                &mut size,
1430                flags as libc::c_uint,
1431            )
1432        };
1433        if ret == -1 {
1434            return Err(Error::last_error());
1435        }
1436        Ok(size)
1437    }
1438
1439    pub fn migrate_set_max_downtime(&self, downtime: u64, flags: u32) -> Result<u32, Error> {
1440        let ret = unsafe {
1441            sys::virDomainMigrateSetMaxDowntime(
1442                self.as_ptr(),
1443                downtime as libc::c_ulonglong,
1444                flags as libc::c_uint,
1445            )
1446        };
1447        if ret == -1 {
1448            return Err(Error::last_error());
1449        }
1450        Ok(ret as u32)
1451    }
1452
1453    pub fn set_time(&self, seconds: i64, nseconds: i32, flags: u32) -> Result<u32, Error> {
1454        let ret = unsafe {
1455            sys::virDomainSetTime(
1456                self.as_ptr(),
1457                seconds as libc::c_longlong,
1458                nseconds as libc::c_uint,
1459                flags as libc::c_uint,
1460            )
1461        };
1462        if ret == -1 {
1463            return Err(Error::last_error());
1464        }
1465        Ok(ret as u32)
1466    }
1467
1468    pub fn get_time(&self, flags: u32) -> Result<(i64, i32), Error> {
1469        let mut seconds: libc::c_longlong = 0;
1470        let mut nseconds: libc::c_uint = 0;
1471        let ret = unsafe {
1472            sys::virDomainGetTime(
1473                self.as_ptr(),
1474                &mut seconds,
1475                &mut nseconds,
1476                flags as libc::c_uint,
1477            )
1478        };
1479        if ret == -1 {
1480            return Err(Error::last_error());
1481        }
1482        Ok((seconds, nseconds as i32))
1483    }
1484
1485    pub fn get_block_info(&self, disk: &str, flags: u32) -> Result<BlockInfo, Error> {
1486        let mut pinfo = mem::MaybeUninit::uninit();
1487        let disk_buf = CString::new(disk).unwrap();
1488        let ret = unsafe {
1489            sys::virDomainGetBlockInfo(
1490                self.as_ptr(),
1491                disk_buf.as_ptr(),
1492                pinfo.as_mut_ptr(),
1493                flags as libc::c_uint,
1494            )
1495        };
1496        if ret == -1 {
1497            return Err(Error::last_error());
1498        }
1499        Ok(unsafe { BlockInfo::from_ptr(&mut pinfo.assume_init()) })
1500    }
1501
1502    pub fn get_block_stats(&self, disk: &str) -> Result<BlockStats, Error> {
1503        let mut pinfo = mem::MaybeUninit::uninit();
1504        let disk_buf = CString::new(disk).unwrap();
1505        let ret = unsafe {
1506            sys::virDomainBlockStats(
1507                self.as_ptr(),
1508                disk_buf.as_ptr(),
1509                pinfo.as_mut_ptr(),
1510                mem::size_of::<sys::virDomainBlockStatsStruct>(),
1511            )
1512        };
1513        if ret == -1 {
1514            return Err(Error::last_error());
1515        }
1516        Ok(unsafe { BlockStats::from_ptr(&mut pinfo.assume_init()) })
1517    }
1518
1519    pub fn pin_vcpu(&self, vcpu: u32, cpumap: &[u8]) -> Result<u32, Error> {
1520        let ret = unsafe {
1521            sys::virDomainPinVcpu(
1522                self.as_ptr(),
1523                vcpu as libc::c_uint,
1524                cpumap.as_ptr() as *mut _,
1525                cpumap.len() as libc::c_int,
1526            )
1527        };
1528        if ret == -1 {
1529            return Err(Error::last_error());
1530        }
1531        Ok(ret as u32)
1532    }
1533
1534    pub fn pin_vcpu_flags(&self, vcpu: u32, cpumap: &[u8], flags: u32) -> Result<u32, Error> {
1535        let ret = unsafe {
1536            sys::virDomainPinVcpuFlags(
1537                self.as_ptr(),
1538                vcpu as libc::c_uint,
1539                cpumap.as_ptr() as *mut _,
1540                cpumap.len() as libc::c_int,
1541                flags as libc::c_uint,
1542            )
1543        };
1544        if ret == -1 {
1545            return Err(Error::last_error());
1546        }
1547        Ok(ret as u32)
1548    }
1549
1550    pub fn pin_emulator(&self, cpumap: &[u8], flags: u32) -> Result<u32, Error> {
1551        let ret = unsafe {
1552            sys::virDomainPinEmulator(
1553                self.as_ptr(),
1554                cpumap.as_ptr() as *mut _,
1555                cpumap.len() as libc::c_int,
1556                flags as libc::c_uint,
1557            )
1558        };
1559        if ret == -1 {
1560            return Err(Error::last_error());
1561        }
1562        Ok(ret as u32)
1563    }
1564
1565    pub fn rename(&self, new_name: &str, flags: u32) -> Result<u32, Error> {
1566        let new_name_buf = CString::new(new_name).unwrap();
1567        let ret = unsafe {
1568            sys::virDomainRename(self.as_ptr(), new_name_buf.as_ptr(), flags as libc::c_uint)
1569        };
1570        if ret == -1 {
1571            return Err(Error::last_error());
1572        }
1573        Ok(ret as u32)
1574    }
1575
1576    pub fn set_user_password(&self, user: &str, password: &str, flags: u32) -> Result<u32, Error> {
1577        let user_buf = CString::new(user).unwrap();
1578        let password_buf = CString::new(password).unwrap();
1579        let ret = unsafe {
1580            sys::virDomainSetUserPassword(
1581                self.as_ptr(),
1582                user_buf.as_ptr(),
1583                password_buf.as_ptr(),
1584                flags as libc::c_uint,
1585            )
1586        };
1587        if ret == -1 {
1588            return Err(Error::last_error());
1589        }
1590        Ok(ret as u32)
1591    }
1592
1593    pub fn set_block_threshold(&self, dev: &str, threshold: u64, flags: u32) -> Result<u32, Error> {
1594        let dev_buf = CString::new(dev).unwrap();
1595        let ret = unsafe {
1596            sys::virDomainSetBlockThreshold(
1597                self.as_ptr(),
1598                dev_buf.as_ptr(),
1599                threshold as libc::c_ulonglong,
1600                flags as libc::c_uint,
1601            )
1602        };
1603        if ret == -1 {
1604            return Err(Error::last_error());
1605        }
1606        Ok(ret as u32)
1607    }
1608
1609    pub fn open_graphics(&self, idx: u32, fd: i32, flags: u32) -> Result<u32, Error> {
1610        let ret = unsafe {
1611            sys::virDomainOpenGraphics(
1612                self.as_ptr(),
1613                idx as libc::c_uint,
1614                fd as libc::c_int,
1615                flags as libc::c_uint,
1616            )
1617        };
1618        if ret == -1 {
1619            return Err(Error::last_error());
1620        }
1621        Ok(ret as u32)
1622    }
1623
1624    pub fn open_graphics_fd(&self, idx: u32, flags: u32) -> Result<u32, Error> {
1625        let ret = unsafe {
1626            sys::virDomainOpenGraphicsFD(self.as_ptr(), idx as libc::c_uint, flags as libc::c_uint)
1627        };
1628        if ret == -1 {
1629            return Err(Error::last_error());
1630        }
1631        Ok(ret as u32)
1632    }
1633
1634    pub fn open_channel(
1635        &self,
1636        name: Option<&str>,
1637        stream: &Stream,
1638        flags: u32,
1639    ) -> Result<u32, Error> {
1640        let name_buf = some_string_to_cstring!(name);
1641        let ret = unsafe {
1642            sys::virDomainOpenChannel(
1643                self.as_ptr(),
1644                some_cstring_to_c_chars!(name_buf),
1645                stream.as_ptr(),
1646                flags as libc::c_uint,
1647            )
1648        };
1649        if ret == -1 {
1650            return Err(Error::last_error());
1651        }
1652        Ok(ret as u32)
1653    }
1654
1655    pub fn open_console(
1656        &self,
1657        name: Option<&str>,
1658        stream: &Stream,
1659        flags: u32,
1660    ) -> Result<u32, Error> {
1661        let name_buf = some_string_to_cstring!(name);
1662        let ret = unsafe {
1663            sys::virDomainOpenConsole(
1664                self.as_ptr(),
1665                some_cstring_to_c_chars!(name_buf),
1666                stream.as_ptr(),
1667                flags as libc::c_uint,
1668            )
1669        };
1670        if ret == -1 {
1671            return Err(Error::last_error());
1672        }
1673        Ok(ret as u32)
1674    }
1675
1676    pub fn interface_addresses(
1677        &self,
1678        source: sys::virDomainInterfaceAddressesSource,
1679        flags: u32,
1680    ) -> Result<Vec<Interface>, Error> {
1681        let mut addresses: *mut sys::virDomainInterfacePtr = ptr::null_mut();
1682        let size = unsafe {
1683            sys::virDomainInterfaceAddresses(self.as_ptr(), &mut addresses, source, flags)
1684        };
1685        if size == -1 {
1686            return Err(Error::last_error());
1687        }
1688
1689        let mut array: Vec<Interface> = Vec::new();
1690        for x in 0..size as isize {
1691            array.push(unsafe { Interface::from_ptr(*addresses.offset(x)) });
1692        }
1693        unsafe { libc::free(addresses as *mut libc::c_void) };
1694
1695        Ok(array)
1696    }
1697
1698    pub fn interface_stats(&self, path: &str) -> Result<InterfaceStats, Error> {
1699        let mut pinfo = mem::MaybeUninit::uninit();
1700        let path_buf = CString::new(path).unwrap();
1701        let ret = unsafe {
1702            sys::virDomainInterfaceStats(
1703                self.as_ptr(),
1704                path_buf.as_ptr(),
1705                pinfo.as_mut_ptr(),
1706                mem::size_of::<sys::virDomainInterfaceStatsStruct>(),
1707            )
1708        };
1709        if ret == -1 {
1710            return Err(Error::last_error());
1711        }
1712        Ok(unsafe { InterfaceStats::from_ptr(&mut pinfo.assume_init()) })
1713    }
1714
1715    pub fn memory_stats(&self, flags: u32) -> Result<Vec<MemoryStat>, Error> {
1716        let mut pinfo: Vec<sys::virDomainMemoryStatStruct> =
1717            Vec::with_capacity(sys::VIR_DOMAIN_MEMORY_STAT_NR as usize);
1718        let ret = unsafe {
1719            sys::virDomainMemoryStats(
1720                self.as_ptr(),
1721                pinfo.as_mut_ptr(),
1722                sys::VIR_DOMAIN_MEMORY_STAT_NR,
1723                flags as libc::c_uint,
1724            )
1725        };
1726        if ret == -1 {
1727            return Err(Error::last_error());
1728        }
1729        // low-level operation that is confirmed by return from
1730        // libvirt.
1731        unsafe { pinfo.set_len(ret as usize) };
1732
1733        let mut stats: Vec<MemoryStat> = Vec::with_capacity(ret as usize);
1734        for x in pinfo.iter().take(ret as usize) {
1735            stats.push(unsafe { MemoryStat::from_ptr(x) });
1736        }
1737        Ok(stats)
1738    }
1739
1740    /// Get progress statistics about a background job running on this domain.
1741    /// This method will return an error if the domain isn't active
1742    pub fn get_job_stats(&self, flags: sys::virDomainGetJobStatsFlags) -> Result<JobStats, Error> {
1743        let mut r#type: libc::c_int = 0;
1744
1745        // We allow libvirt to allocate the params structure for us. libvirt will populate
1746        // nparams with the number of typed params returned.
1747        let mut nparams: libc::c_int = 0;
1748        let mut params: sys::virTypedParameterPtr = ptr::null_mut();
1749
1750        let ret = unsafe {
1751            sys::virDomainGetJobStats(
1752                self.as_ptr(),
1753                &mut r#type,
1754                &mut params,
1755                &mut nparams,
1756                flags as libc::c_uint,
1757            )
1758        };
1759
1760        if ret == -1 {
1761            return Err(Error::last_error());
1762        }
1763
1764        let res: Vec<sys::virTypedParameter> =
1765            unsafe { Vec::from_raw_parts(params, nparams as usize, nparams as usize) };
1766
1767        Ok((r#type, res).into())
1768    }
1769
1770    /// Get progress information about a background job running on this domain.
1771    /// NOTE: Only a subset of the fields in JobStats are populated by this method. If you want to
1772    /// populate more fields then you should use [`Self::get_job_stats`].
1773    pub fn get_job_info(&self) -> Result<JobStats, Error> {
1774        unsafe {
1775            let mut job_info = mem::MaybeUninit::uninit();
1776            let ret = sys::virDomainGetJobInfo(self.as_ptr(), job_info.as_mut_ptr());
1777
1778            if ret == -1 {
1779                return Err(Error::last_error());
1780            }
1781
1782            let ptr: sys::virDomainJobInfoPtr = &mut job_info.assume_init();
1783
1784            Ok(JobStats {
1785                r#type: (*ptr).type_,
1786                time_elapsed: Some((*ptr).timeElapsed as u64),
1787                time_remaining: Some((*ptr).timeRemaining as u64),
1788                data_total: Some((*ptr).dataTotal as u64),
1789                data_processed: Some((*ptr).dataProcessed as u64),
1790                data_remaining: Some((*ptr).dataRemaining as u64),
1791                mem_total: Some((*ptr).memTotal as u64),
1792                mem_processed: Some((*ptr).memProcessed as u64),
1793                mem_remaining: Some((*ptr).memRemaining as u64),
1794                disk_total: Some((*ptr).fileTotal as u64),
1795                disk_processed: Some((*ptr).fileProcessed as u64),
1796                disk_remaining: Some((*ptr).fileRemaining as u64),
1797                ..Default::default()
1798            })
1799        }
1800    }
1801
1802    pub fn save_image_get_xml_desc(
1803        conn: &Connect,
1804        file: &str,
1805        flags: u32,
1806    ) -> Result<String, Error> {
1807        let file_buf = CString::new(file).unwrap();
1808        let ptr = unsafe {
1809            sys::virDomainSaveImageGetXMLDesc(
1810                conn.as_ptr(),
1811                file_buf.as_ptr(),
1812                flags as libc::c_uint,
1813            )
1814        };
1815        if ptr.is_null() {
1816            return Err(Error::last_error());
1817        }
1818        Ok(unsafe { c_chars_to_string!(ptr) })
1819    }
1820
1821    pub fn save_image_define_xml(
1822        conn: &Connect,
1823        file: &str,
1824        dxml: &str,
1825        flags: u32,
1826    ) -> Result<u32, Error> {
1827        let file_buf = CString::new(file).unwrap();
1828        let dxml_buf = CString::new(dxml).unwrap();
1829        let ret = unsafe {
1830            sys::virDomainSaveImageDefineXML(
1831                conn.as_ptr(),
1832                file_buf.as_ptr(),
1833                dxml_buf.as_ptr(),
1834                flags as libc::c_uint,
1835            )
1836        };
1837        if ret == -1 {
1838            return Err(Error::last_error());
1839        }
1840        Ok(ret as u32)
1841    }
1842
1843    pub fn attach_device(&self, xml: &str) -> Result<u32, Error> {
1844        let xml_buf = CString::new(xml).unwrap();
1845        let ret = unsafe { sys::virDomainAttachDevice(self.as_ptr(), xml_buf.as_ptr()) };
1846        if ret == -1 {
1847            return Err(Error::last_error());
1848        }
1849        Ok(ret as u32)
1850    }
1851
1852    pub fn attach_device_flags(&self, xml: &str, flags: u32) -> Result<u32, Error> {
1853        let xml_buf = CString::new(xml).unwrap();
1854        let ret = unsafe {
1855            sys::virDomainAttachDeviceFlags(self.as_ptr(), xml_buf.as_ptr(), flags as libc::c_uint)
1856        };
1857        if ret == -1 {
1858            return Err(Error::last_error());
1859        }
1860        Ok(ret as u32)
1861    }
1862
1863    pub fn detach_device(&self, xml: &str) -> Result<u32, Error> {
1864        let xml_buf = CString::new(xml).unwrap();
1865        let ret = unsafe { sys::virDomainDetachDevice(self.as_ptr(), xml_buf.as_ptr()) };
1866        if ret == -1 {
1867            return Err(Error::last_error());
1868        }
1869        Ok(ret as u32)
1870    }
1871
1872    pub fn detach_device_flags(&self, xml: &str, flags: u32) -> Result<u32, Error> {
1873        let xml_buf = CString::new(xml).unwrap();
1874        let ret = unsafe {
1875            sys::virDomainDetachDeviceFlags(self.as_ptr(), xml_buf.as_ptr(), flags as libc::c_uint)
1876        };
1877        if ret == -1 {
1878            return Err(Error::last_error());
1879        }
1880        Ok(ret as u32)
1881    }
1882
1883    pub fn update_device_flags(&self, xml: &str, flags: u32) -> Result<u32, Error> {
1884        let xml_buf = CString::new(xml).unwrap();
1885        let ret = unsafe {
1886            sys::virDomainUpdateDeviceFlags(self.as_ptr(), xml_buf.as_ptr(), flags as libc::c_uint)
1887        };
1888        if ret == -1 {
1889            return Err(Error::last_error());
1890        }
1891        Ok(ret as u32)
1892    }
1893
1894    pub fn managed_save(&self, flags: u32) -> Result<u32, Error> {
1895        let ret = unsafe { sys::virDomainManagedSave(self.as_ptr(), flags as libc::c_uint) };
1896        if ret == -1 {
1897            return Err(Error::last_error());
1898        }
1899        Ok(ret as u32)
1900    }
1901
1902    pub fn has_managed_save(&self, flags: u32) -> Result<bool, Error> {
1903        let ret =
1904            unsafe { sys::virDomainHasManagedSaveImage(self.as_ptr(), flags as libc::c_uint) };
1905        if ret == -1 {
1906            return Err(Error::last_error());
1907        }
1908        Ok(ret == 1)
1909    }
1910
1911    pub fn managed_save_remove(&self, flags: u32) -> Result<u32, Error> {
1912        let ret = unsafe { sys::virDomainManagedSaveRemove(self.as_ptr(), flags as libc::c_uint) };
1913        if ret == -1 {
1914            return Err(Error::last_error());
1915        }
1916        Ok(ret as u32)
1917    }
1918
1919    pub fn core_dump(&self, to: &str, flags: u32) -> Result<u32, Error> {
1920        let to_buf = CString::new(to).unwrap();
1921        let ret = unsafe {
1922            sys::virDomainCoreDump(self.as_ptr(), to_buf.as_ptr(), flags as libc::c_uint)
1923        };
1924        if ret == -1 {
1925            return Err(Error::last_error());
1926        }
1927        Ok(ret as u32)
1928    }
1929
1930    pub fn core_dump_with_format(&self, to: &str, format: u32, flags: u32) -> Result<u32, Error> {
1931        let to_buf = CString::new(to).unwrap();
1932        let ret = unsafe {
1933            sys::virDomainCoreDumpWithFormat(
1934                self.as_ptr(),
1935                to_buf.as_ptr(),
1936                format as libc::c_uint,
1937                flags as libc::c_uint,
1938            )
1939        };
1940        if ret == -1 {
1941            return Err(Error::last_error());
1942        }
1943        Ok(ret as u32)
1944    }
1945
1946    pub fn set_metadata(
1947        &self,
1948        kind: i32,
1949        metadata: Option<&str>,
1950        key: Option<&str>,
1951        uri: Option<&str>,
1952        flags: u32,
1953    ) -> Result<u32, Error> {
1954        let metadata_buf = some_string_to_cstring!(metadata);
1955        let key_buf = some_string_to_cstring!(key);
1956        let uri_buf = some_string_to_cstring!(uri);
1957        let ret = unsafe {
1958            sys::virDomainSetMetadata(
1959                self.as_ptr(),
1960                kind as libc::c_int,
1961                some_cstring_to_c_chars!(metadata_buf),
1962                some_cstring_to_c_chars!(key_buf),
1963                some_cstring_to_c_chars!(uri_buf),
1964                flags as libc::c_uint,
1965            )
1966        };
1967        if ret == -1 {
1968            return Err(Error::last_error());
1969        }
1970        Ok(ret as u32)
1971    }
1972
1973    pub fn get_metadata(&self, kind: i32, uri: Option<&str>, flags: u32) -> Result<String, Error> {
1974        let uri_buf = some_string_to_cstring!(uri);
1975        let n = unsafe {
1976            sys::virDomainGetMetadata(
1977                self.as_ptr(),
1978                kind as libc::c_int,
1979                some_cstring_to_c_chars!(uri_buf),
1980                flags as libc::c_uint,
1981            )
1982        };
1983        if n.is_null() {
1984            return Err(Error::last_error());
1985        }
1986        Ok(unsafe { c_chars_to_string!(n) })
1987    }
1988
1989    pub fn block_resize(&self, disk: &str, size: u64, flags: u32) -> Result<u32, Error> {
1990        let disk_buf = CString::new(disk).unwrap();
1991        let ret = unsafe {
1992            sys::virDomainBlockResize(
1993                self.as_ptr(),
1994                disk_buf.as_ptr(),
1995                size as libc::c_ulonglong,
1996                flags as libc::c_uint,
1997            )
1998        };
1999        if ret == -1 {
2000            return Err(Error::last_error());
2001        }
2002        Ok(ret as u32)
2003    }
2004
2005    pub fn get_memory_parameters(&self, flags: u32) -> Result<MemoryParameters, Error> {
2006        let mut nparams: libc::c_int = 0;
2007        let ret = unsafe {
2008            sys::virDomainGetMemoryParameters(
2009                self.as_ptr(),
2010                ptr::null_mut(),
2011                &mut nparams,
2012                flags as libc::c_uint,
2013            )
2014        };
2015        if ret == -1 {
2016            return Err(Error::last_error());
2017        }
2018        let mut params: Vec<sys::virTypedParameter> = Vec::with_capacity(nparams as usize);
2019        let ret = unsafe {
2020            sys::virDomainGetMemoryParameters(
2021                self.as_ptr(),
2022                params.as_mut_ptr(),
2023                &mut nparams,
2024                flags as libc::c_uint,
2025            )
2026        };
2027        if ret == -1 {
2028            return Err(Error::last_error());
2029        }
2030        unsafe { params.set_len(nparams as usize) };
2031        Ok(MemoryParameters::from_vec(params))
2032    }
2033
2034    pub fn set_memory_parameters(
2035        &self,
2036        params: MemoryParameters,
2037        flags: u32,
2038    ) -> Result<u32, Error> {
2039        let mut cparams = params.to_vec();
2040
2041        let ret = unsafe {
2042            sys::virDomainSetMemoryParameters(
2043                self.as_ptr(),
2044                cparams.as_mut_ptr(),
2045                cparams.len() as libc::c_int,
2046                flags as libc::c_uint,
2047            )
2048        };
2049        if ret == -1 {
2050            return Err(Error::last_error());
2051        }
2052        Ok(ret as u32)
2053    }
2054
2055    pub fn migrate(
2056        &self,
2057        dconn: &Connect,
2058        flags: u32,
2059        dname: Option<&str>,
2060        uri: Option<&str>,
2061        bandwidth: u64,
2062    ) -> Result<Domain, Error> {
2063        let dname_buf = some_string_to_cstring!(dname);
2064        let uri_buf = some_string_to_cstring!(uri);
2065        let ptr = unsafe {
2066            sys::virDomainMigrate(
2067                self.as_ptr(),
2068                dconn.as_ptr(),
2069                flags as libc::c_ulong,
2070                some_cstring_to_c_chars!(dname_buf),
2071                some_cstring_to_c_chars!(uri_buf),
2072                bandwidth as libc::c_ulong,
2073            )
2074        };
2075        if ptr.is_null() {
2076            return Err(Error::last_error());
2077        }
2078        Ok(unsafe { Domain::from_ptr(ptr) })
2079    }
2080
2081    pub fn migrate2(
2082        &self,
2083        dconn: &Connect,
2084        dxml: Option<&str>,
2085        flags: u32,
2086        dname: Option<&str>,
2087        uri: Option<&str>,
2088        bandwidth: u64,
2089    ) -> Result<Domain, Error> {
2090        let dxml_buf = some_string_to_cstring!(dxml);
2091        let dname_buf = some_string_to_cstring!(dname);
2092        let uri_buf = some_string_to_cstring!(uri);
2093        let ptr = unsafe {
2094            sys::virDomainMigrate2(
2095                self.as_ptr(),
2096                dconn.as_ptr(),
2097                some_cstring_to_c_chars!(dxml_buf),
2098                flags as libc::c_ulong,
2099                some_cstring_to_c_chars!(dname_buf),
2100                some_cstring_to_c_chars!(uri_buf),
2101                bandwidth as libc::c_ulong,
2102            )
2103        };
2104        if ptr.is_null() {
2105            return Err(Error::last_error());
2106        }
2107        Ok(unsafe { Domain::from_ptr(ptr) })
2108    }
2109
2110    pub fn migrate3(
2111        &self,
2112        dconn: &Connect,
2113        parameters: MigrateParameters,
2114        flags: u32,
2115    ) -> Result<Domain, Error> {
2116        let params = parameters.to_vec();
2117        let ptr = unsafe {
2118            sys::virDomainMigrate3(
2119                self.as_ptr(),
2120                dconn.as_ptr(),
2121                params.clone().as_mut_ptr(),
2122                params.len() as libc::c_uint,
2123                flags as libc::c_uint,
2124            )
2125        };
2126        if ptr.is_null() {
2127            return Err(Error::last_error());
2128        }
2129        Ok(unsafe { Domain::from_ptr(ptr) })
2130    }
2131
2132    pub fn migrate_to_uri(
2133        &self,
2134        duri: &str,
2135        flags: u32,
2136        dname: Option<&str>,
2137        bandwidth: u64,
2138    ) -> Result<(), Error> {
2139        let duri_buf = CString::new(duri).unwrap();
2140        let dname_buf = some_string_to_cstring!(dname);
2141        let ret = unsafe {
2142            sys::virDomainMigrateToURI(
2143                self.as_ptr(),
2144                duri_buf.as_ptr(),
2145                flags as libc::c_ulong,
2146                some_cstring_to_c_chars!(dname_buf),
2147                bandwidth as libc::c_ulong,
2148            )
2149        };
2150        if ret == -1 {
2151            return Err(Error::last_error());
2152        }
2153        Ok(())
2154    }
2155
2156    pub fn migrate_to_uri2(
2157        &self,
2158        dconn_uri: Option<&str>,
2159        mig_uri: Option<&str>,
2160        dxml: Option<&str>,
2161        flags: u32,
2162        dname: Option<&str>,
2163        bandwidth: u64,
2164    ) -> Result<(), Error> {
2165        let dconn_uri_buf = some_string_to_cstring!(dconn_uri);
2166        let mig_uri_buf = some_string_to_cstring!(mig_uri);
2167        let dxml_buf = some_string_to_cstring!(dxml);
2168        let dname_buf = some_string_to_cstring!(dname);
2169        let ret = unsafe {
2170            sys::virDomainMigrateToURI2(
2171                self.as_ptr(),
2172                some_cstring_to_c_chars!(dconn_uri_buf),
2173                some_cstring_to_c_chars!(mig_uri_buf),
2174                some_cstring_to_c_chars!(dxml_buf),
2175                flags as libc::c_ulong,
2176                some_cstring_to_c_chars!(dname_buf),
2177                bandwidth as libc::c_ulong,
2178            )
2179        };
2180        if ret == -1 {
2181            return Err(Error::last_error());
2182        }
2183        Ok(())
2184    }
2185
2186    pub fn migrate_to_uri3(
2187        &self,
2188        dconn_uri: Option<&str>,
2189        parameters: MigrateParameters,
2190        flags: u32,
2191    ) -> Result<(), Error> {
2192        let params = parameters.to_vec();
2193        let dconn_uri_buf = some_string_to_cstring!(dconn_uri);
2194        let ret = unsafe {
2195            sys::virDomainMigrateToURI3(
2196                self.as_ptr(),
2197                some_cstring_to_c_chars!(dconn_uri_buf),
2198                params.clone().as_mut_ptr(),
2199                params.len() as libc::c_uint,
2200                flags as libc::c_uint,
2201            )
2202        };
2203        if ret == -1 {
2204            return Err(Error::last_error());
2205        }
2206        Ok(())
2207    }
2208
2209    pub fn get_numa_parameters(&self, flags: u32) -> Result<NUMAParameters, Error> {
2210        let mut nparams: libc::c_int = 0;
2211        let ret = unsafe {
2212            sys::virDomainGetNumaParameters(
2213                self.as_ptr(),
2214                ptr::null_mut(),
2215                &mut nparams,
2216                flags as libc::c_uint,
2217            )
2218        };
2219        if ret == -1 {
2220            return Err(Error::last_error());
2221        }
2222        let mut params: Vec<sys::virTypedParameter> = Vec::with_capacity(nparams as usize);
2223        let ret = unsafe {
2224            sys::virDomainGetNumaParameters(
2225                self.as_ptr(),
2226                params.as_mut_ptr(),
2227                &mut nparams,
2228                flags as libc::c_uint,
2229            )
2230        };
2231        if ret == -1 {
2232            return Err(Error::last_error());
2233        }
2234        unsafe { params.set_len(nparams as usize) };
2235        let nparams = NUMAParameters::from_vec(params.clone());
2236        unsafe { typed_params_release_c_chars!(params) };
2237
2238        Ok(nparams)
2239    }
2240
2241    pub fn set_numa_parameters(&self, params: NUMAParameters, flags: u32) -> Result<u32, Error> {
2242        let mut cparams = params.to_vec();
2243        let ret = unsafe {
2244            sys::virDomainSetNumaParameters(
2245                self.as_ptr(),
2246                cparams.as_mut_ptr(),
2247                cparams.len() as libc::c_int,
2248                flags as libc::c_uint,
2249            )
2250        };
2251        unsafe { typed_params_release_c_chars!(cparams) };
2252        if ret == -1 {
2253            return Err(Error::last_error());
2254        }
2255        Ok(ret as u32)
2256    }
2257
2258    pub fn list_all_snapshots(&self, flags: u32) -> Result<Vec<DomainSnapshot>, Error> {
2259        let mut snaps: *mut sys::virDomainSnapshotPtr = ptr::null_mut();
2260        let size = unsafe {
2261            sys::virDomainListAllSnapshots(self.as_ptr(), &mut snaps, flags as libc::c_uint)
2262        };
2263        if size == -1 {
2264            return Err(Error::last_error());
2265        }
2266
2267        let mut array: Vec<DomainSnapshot> = Vec::new();
2268        for x in 0..size as isize {
2269            array.push(unsafe { DomainSnapshot::from_ptr(*snaps.offset(x)) });
2270        }
2271        unsafe { libc::free(snaps as *mut libc::c_void) };
2272
2273        Ok(array)
2274    }
2275
2276    /// Get the cpu scheduler type for the domain
2277    pub fn get_scheduler_type(&self) -> Result<(String, i32), Error> {
2278        let mut nparams: libc::c_int = -1;
2279        let sched_type = unsafe { sys::virDomainGetSchedulerType(self.as_ptr(), &mut nparams) };
2280        if sched_type.is_null() {
2281            return Err(Error::last_error());
2282        }
2283
2284        Ok((unsafe { c_chars_to_string!(sched_type) }, nparams))
2285    }
2286
2287    /// Get the scheduler parameters for the domain.
2288    pub fn get_scheduler_parameters(&self) -> Result<SchedulerInfo, Error> {
2289        let (sched_type, mut nparams) = self.get_scheduler_type()?;
2290        let mut params: Vec<sys::virTypedParameter> = Vec::with_capacity(nparams as usize);
2291        let ret = unsafe {
2292            sys::virDomainGetSchedulerParameters(self.as_ptr(), params.as_mut_ptr(), &mut nparams)
2293        };
2294        if ret == -1 {
2295            return Err(Error::last_error());
2296        }
2297        unsafe { params.set_len(nparams as usize) };
2298        Ok(SchedulerInfo::from_vec(params, sched_type))
2299    }
2300
2301    /// Get the scheduler parameters for the domain for the configuration
2302    /// as specified by the flags.
2303    /// # Arguments
2304    ///
2305    /// * `flags` - Specifies the domain modification [`Impact`]: [`VIR_DOMAIN_AFFECT_CURRENT`],
2306    ///   [`VIR_DOMAIN_AFFECT_LIVE`] or [`VIR_DOMAIN_AFFECT_CONFIG`].
2307    ///
2308    /// [`Impact`]: sys::virDomainModificationImpact
2309    /// [`VIR_DOMAIN_AFFECT_CURRENT`]: sys::VIR_DOMAIN_AFFECT_CURRENT
2310    /// [`VIR_DOMAIN_AFFECT_LIVE`]: sys::VIR_DOMAIN_AFFECT_LIVE
2311    /// [`VIR_DOMAIN_AFFECT_CONFIG`]: sys::VIR_DOMAIN_AFFECT_CONFIG
2312    pub fn get_scheduler_parameters_flags(
2313        &self,
2314        flags: sys::virDomainModificationImpact,
2315    ) -> Result<SchedulerInfo, Error> {
2316        let (sched_type, mut nparams) = self.get_scheduler_type()?;
2317        let mut params: Vec<sys::virTypedParameter> = Vec::with_capacity(nparams as usize);
2318        let ret = unsafe {
2319            sys::virDomainGetSchedulerParametersFlags(
2320                self.as_ptr(),
2321                params.as_mut_ptr(),
2322                &mut nparams,
2323                flags as libc::c_uint,
2324            )
2325        };
2326        if ret == -1 {
2327            return Err(Error::last_error());
2328        }
2329        unsafe { params.set_len(nparams as usize) };
2330        Ok(SchedulerInfo::from_vec(params, sched_type))
2331    }
2332
2333    /// Set the scheduler parameters for the domain.
2334    pub fn set_scheduler_parameters(&self, sched_info: &SchedulerInfo) -> Result<i32, Error> {
2335        let mut params = sched_info.to_vec();
2336        let ret = unsafe {
2337            sys::virDomainSetSchedulerParameters(
2338                self.as_ptr(),
2339                params.as_mut_ptr(),
2340                params.len() as libc::c_int,
2341            )
2342        };
2343        if ret == -1 {
2344            return Err(Error::last_error());
2345        }
2346        Ok(ret)
2347    }
2348
2349    /// Set the scheduler parameters for the domain for the configuration
2350    /// as specified by the flags.
2351    /// # Arguments
2352    ///
2353    /// * `flags` - Specifies the domain modification [`Impact`]: [`VIR_DOMAIN_AFFECT_CURRENT`],
2354    ///   [`VIR_DOMAIN_AFFECT_LIVE`] or [`VIR_DOMAIN_AFFECT_CONFIG`].
2355    ///
2356    /// [`Impact`]: sys::virDomainModificationImpact
2357    /// [`VIR_DOMAIN_AFFECT_CURRENT`]: sys::VIR_DOMAIN_AFFECT_CURRENT
2358    /// [`VIR_DOMAIN_AFFECT_LIVE`]: sys::VIR_DOMAIN_AFFECT_LIVE
2359    /// [`VIR_DOMAIN_AFFECT_CONFIG`]: sys::VIR_DOMAIN_AFFECT_CONFIG
2360    pub fn set_scheduler_parameters_flags(
2361        &self,
2362        sched_info: &SchedulerInfo,
2363        flags: sys::virDomainModificationImpact,
2364    ) -> Result<i32, Error> {
2365        let mut params = sched_info.to_vec();
2366        let ret = unsafe {
2367            sys::virDomainSetSchedulerParametersFlags(
2368                self.as_ptr(),
2369                params.as_mut_ptr(),
2370                params.len() as libc::c_int,
2371                flags as libc::c_uint,
2372            )
2373        };
2374        if ret == -1 {
2375            return Err(Error::last_error());
2376        }
2377        Ok(ret)
2378    }
2379
2380    /// Send key(s) to the guest.
2381    /// # Arguments
2382    ///
2383    /// * `codeset` - Specifies the code set of keycodes.
2384    /// * `holdtime` - Specifies the duration (in milliseconds) that the keys will be held.
2385    /// * `keycodes` - Specifies the array of keycodes.
2386    /// * `nkeycodes` - Specifies the number of keycodes.
2387    /// * `flags` - Extra flags; not used yet, so callers should always pass 0..
2388    pub fn send_key(
2389        &self,
2390        codeset: sys::virKeycodeSet,
2391        holdtime: u32,
2392        keycodes: *mut u32,
2393        nkeycodes: i32,
2394        flags: u32,
2395    ) -> Result<(), Error> {
2396        let ret = unsafe {
2397            sys::virDomainSendKey(
2398                self.as_ptr(),
2399                codeset as libc::c_uint,
2400                holdtime as libc::c_uint,
2401                keycodes as *mut libc::c_uint,
2402                nkeycodes as libc::c_int,
2403                flags as libc::c_uint,
2404            )
2405        };
2406        if ret == -1 {
2407            return Err(Error::last_error());
2408        }
2409        Ok(())
2410    }
2411
2412    /// Take a screenshot of current domain console as a stream.
2413    /// Returns a string representing the mime-type of the image format.
2414    /// # Arguments
2415    ///
2416    /// * `domain` - a domain object
2417    /// * `stream` - stream to use as output
2418    /// * `screen` - monitor ID to take screenshot from
2419    /// * `flags` - extra flags; not used yet, so callers should always pass 0
2420    pub fn screenshot(&self, stream: &Stream, screen: u32, flags: u32) -> Result<String, Error> {
2421        let n = unsafe {
2422            sys::virDomainScreenshot(
2423                self.as_ptr(),
2424                stream.as_ptr(),
2425                screen as libc::c_uint,
2426                flags as libc::c_uint,
2427            )
2428        };
2429        if n.is_null() {
2430            return Err(Error::last_error());
2431        }
2432        Ok(unsafe { c_chars_to_string!(n) })
2433    }
2434
2435    /// Send an arbitrary monitor command cmd to domain through the QEMU monitor.
2436    ///
2437    /// * `cmd` - the QEMU monitor command string
2438    /// * `flags` - bitwise-or of supported [`virDomainQemuMonitorCommandFlags`]
2439    ///
2440    /// [`virDomainQemuMonitorCommandFlags`]: sys::virDomainQemuMonitorCommandFlags
2441    #[cfg(feature = "qemu")]
2442    pub fn qemu_monitor_command(&self, cmd: &str, flags: u32) -> Result<String, Error> {
2443        let mut result: *mut libc::c_char = std::ptr::null_mut();
2444        let cmd_buf = CString::new(cmd).unwrap();
2445        let ret = unsafe {
2446            sys::virDomainQemuMonitorCommand(
2447                self.as_ptr(),
2448                cmd_buf.as_ptr(),
2449                &mut result,
2450                flags as libc::c_uint,
2451            )
2452        };
2453        if ret == -1 {
2454            return Err(Error::last_error());
2455        }
2456        Ok(unsafe { c_chars_to_string!(result) })
2457    }
2458
2459    /// Send an arbitrary agent command to the domain through the QEMU guest agent.
2460    ///
2461    /// * `cmd` - the QEMU guest agent command string
2462    /// * `flags` - bitwise-or of supported execution flags
2463    /// * `timeout` - the timeout in seconds, or one of the [`virDomainQemuAgentCommandTimeoutValues`] flags
2464    ///
2465    /// [`virDomainQemuAgentCommandTimeoutValues`]: sys::virDomainQemuAgentCommandTimeoutValues
2466    #[cfg(feature = "qemu")]
2467    pub fn qemu_agent_command(&self, cmd: &str, timeout: i32, flags: u32) -> Result<String, Error> {
2468        let cmd_buf = CString::new(cmd).unwrap();
2469        let ret = unsafe {
2470            sys::virDomainQemuAgentCommand(
2471                self.as_ptr(),
2472                cmd_buf.as_ptr(),
2473                timeout as libc::c_int,
2474                flags as libc::c_uint,
2475            )
2476        };
2477
2478        if ret.is_null() {
2479            return Err(Error::last_error());
2480        }
2481        Ok(unsafe { c_chars_to_string!(ret) })
2482    }
2483}