nmstate/
checkpoint.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use std::ffi::{CStr, CString};
4use std::time::SystemTime;
5
6use libc::{c_char, c_int};
7
8use crate::{init_logger, NMSTATE_FAIL, NMSTATE_PASS};
9
10#[allow(clippy::not_unsafe_ptr_arg_deref)]
11#[no_mangle]
12pub extern "C" fn nmstate_checkpoint_commit(
13    checkpoint: *const c_char,
14    log: *mut *mut c_char,
15    err_kind: *mut *mut c_char,
16    err_msg: *mut *mut c_char,
17) -> c_int {
18    assert!(!log.is_null());
19    assert!(!err_kind.is_null());
20    assert!(!err_msg.is_null());
21
22    unsafe {
23        *log = std::ptr::null_mut();
24        *err_kind = std::ptr::null_mut();
25        *err_msg = std::ptr::null_mut();
26    }
27
28    let logger = match init_logger() {
29        Ok(l) => l,
30        Err(e) => {
31            unsafe {
32                *err_msg = CString::new(format!("Failed to setup logger: {e}"))
33                    .unwrap()
34                    .into_raw();
35            }
36            return NMSTATE_FAIL;
37        }
38    };
39    let now = SystemTime::now();
40
41    let mut checkpoint_str = "";
42    if !checkpoint.is_null() {
43        let checkpoint_cstr = unsafe { CStr::from_ptr(checkpoint) };
44        checkpoint_str = match checkpoint_cstr.to_str() {
45            Ok(s) => s,
46            Err(e) => {
47                unsafe {
48                    *err_msg = CString::new(format!(
49                        "Error on converting C char to rust str: {e}"
50                    ))
51                    .unwrap()
52                    .into_raw();
53                    *err_kind = CString::new(format!(
54                        "{}",
55                        nmstate::ErrorKind::InvalidArgument
56                    ))
57                    .unwrap()
58                    .into_raw();
59                }
60                return NMSTATE_FAIL;
61            }
62        }
63    }
64
65    let result = nmstate::NetworkState::checkpoint_commit(checkpoint_str);
66    unsafe {
67        *log = CString::new(logger.drain(now)).unwrap().into_raw();
68    }
69
70    if let Err(e) = result {
71        unsafe {
72            *err_msg = CString::new(e.msg()).unwrap().into_raw();
73            *err_kind =
74                CString::new(format!("{}", &e.kind())).unwrap().into_raw();
75        }
76        NMSTATE_FAIL
77    } else {
78        NMSTATE_PASS
79    }
80}
81
82#[allow(clippy::not_unsafe_ptr_arg_deref)]
83#[no_mangle]
84pub extern "C" fn nmstate_checkpoint_rollback(
85    checkpoint: *const c_char,
86    log: *mut *mut c_char,
87    err_kind: *mut *mut c_char,
88    err_msg: *mut *mut c_char,
89) -> c_int {
90    assert!(!log.is_null());
91    assert!(!err_kind.is_null());
92    assert!(!err_msg.is_null());
93
94    unsafe {
95        *log = std::ptr::null_mut();
96        *err_kind = std::ptr::null_mut();
97        *err_msg = std::ptr::null_mut();
98    }
99
100    let logger = match init_logger() {
101        Ok(l) => l,
102        Err(e) => {
103            unsafe {
104                *err_msg = CString::new(format!("Failed to setup logger: {e}"))
105                    .unwrap()
106                    .into_raw();
107            }
108            return NMSTATE_FAIL;
109        }
110    };
111    let now = SystemTime::now();
112
113    let mut checkpoint_str = "";
114    if !checkpoint.is_null() {
115        let checkpoint_cstr = unsafe { CStr::from_ptr(checkpoint) };
116        checkpoint_str = match checkpoint_cstr.to_str() {
117            Ok(s) => s,
118            Err(e) => {
119                unsafe {
120                    *err_msg = CString::new(format!(
121                        "Error on converting C char to rust str: {e}"
122                    ))
123                    .unwrap()
124                    .into_raw();
125                    *err_kind = CString::new(format!(
126                        "{}",
127                        nmstate::ErrorKind::InvalidArgument
128                    ))
129                    .unwrap()
130                    .into_raw();
131                }
132                return NMSTATE_FAIL;
133            }
134        }
135    }
136
137    // TODO: save log to the output pointer
138    let result = nmstate::NetworkState::checkpoint_rollback(checkpoint_str);
139    unsafe {
140        *log = CString::new(logger.drain(now)).unwrap().into_raw();
141    }
142
143    if let Err(e) = result {
144        unsafe {
145            *err_msg = CString::new(e.msg()).unwrap().into_raw();
146            *err_kind =
147                CString::new(format!("{}", &e.kind())).unwrap().into_raw();
148        }
149        NMSTATE_FAIL
150    } else {
151        NMSTATE_PASS
152    }
153}