1#![allow(non_camel_case_types)]
30
31use super::error::*;
32
33use std::convert::TryFrom;
34use std::ffi::CStr;
35use std::ffi::CString;
36use std::os::raw::c_void;
37use std::os::raw::{c_char, c_int};
38
39enum c_lsm_string_list {}
41enum c_lsm_error {}
42enum c_lsm_led_handle {}
43enum c_lsm_led_slot_itr {}
44enum c_lsm_led_slot {}
45
46#[repr(C)]
48#[derive(Debug, Copy, Clone, PartialEq, Eq)]
49pub enum LinkType {
50 NoSupport = -2,
52 Unknown = -1,
54 Fc = 0,
56 Ssa = 2,
58 Sbp = 3,
60 Srp = 4,
62 Iscsi = 5,
64 Sas = 6,
66 Adt = 7,
68 Ata = 8,
70 Usb = 9,
72 Sop = 10,
74 Pcie = 11,
76}
77
78#[link(name = "storagemgmt")]
79extern "C" {
80
81 fn lsm_local_disk_list(
82 disk_paths: *mut *mut c_lsm_string_list,
83 lsm_error: *mut *mut c_lsm_error,
84 ) -> c_int;
85 fn lsm_string_list_free(lsm_string: *const c_lsm_string_list) -> c_int;
86 fn lsm_string_list_size(lsm_string_list: *const c_lsm_string_list) -> u32;
87 fn lsm_string_list_elem_get(
88 lsm_string_list: *const c_lsm_string_list,
89 index: u32,
90 ) -> *const c_char;
91
92 fn lsm_local_disk_vpd83_search(
93 vpd83: *const c_char,
94 lsm_string_list: *mut *mut c_lsm_string_list,
95 lsm_error: *mut *mut c_lsm_error,
96 ) -> c_int;
97
98 fn lsm_local_disk_serial_num_get(
99 disk_path: *const c_char,
100 serial_num: *mut *mut c_char,
101 lsm_error: *mut *mut c_lsm_error,
102 ) -> c_int;
103
104 fn lsm_local_disk_vpd83_get(
105 disk_path: *const c_char,
106 vpd83: *mut *mut c_char,
107 lsm_error: *mut *mut c_lsm_error,
108 ) -> c_int;
109
110 fn lsm_local_disk_health_status_get(
111 disk_path: *const c_char,
112 health_status: &mut i32,
113 lsm_error: *mut *mut c_lsm_error,
114 ) -> c_int;
115
116 fn lsm_local_disk_rpm_get(
117 disk_path: *const c_char,
118 rpm: &mut i32,
119 lsm_error: *mut *mut c_lsm_error,
120 ) -> c_int;
121
122 fn lsm_local_disk_link_type_get(
123 disk_path: *const c_char,
124 link_type: *mut LinkType,
125 lsm_error: *mut *mut c_lsm_error,
126 ) -> c_int;
127
128 fn lsm_local_disk_ident_led_on(
129 disk_path: *const c_char,
130 lsm_error: *mut *mut c_lsm_error,
131 ) -> c_int;
132
133 fn lsm_local_disk_ident_led_off(
134 disk_path: *const c_char,
135 lsm_error: *mut *mut c_lsm_error,
136 ) -> c_int;
137
138 fn lsm_local_disk_fault_led_on(
139 disk_path: *const c_char,
140 lsm_error: *mut *mut c_lsm_error,
141 ) -> c_int;
142
143 fn lsm_local_disk_fault_led_off(
144 disk_path: *const c_char,
145 lsm_error: *mut *mut c_lsm_error,
146 ) -> c_int;
147
148 fn lsm_local_disk_led_status_get(
149 disk_path: *const c_char,
150 led_status: &mut u32,
151 lsm_error: *mut *mut c_lsm_error,
152 ) -> c_int;
153
154 fn lsm_local_disk_link_speed_get(
155 disk_path: *const c_char,
156 link_speed: &mut u32,
157 lsm_error: *mut *mut c_lsm_error,
158 ) -> c_int;
159
160 fn lsm_error_number_get(lsm_error: *const c_lsm_error) -> c_int;
161 fn lsm_error_message_get(lsm_error: *const c_lsm_error) -> *const c_char;
162 fn lsm_error_free(lsm_error: *const c_lsm_error) -> c_int;
163
164 fn lsm_led_handle_get(handle: *mut *mut c_lsm_led_handle, flags: u64) -> c_int;
165 fn lsm_led_handle_free(handle: *const c_lsm_led_handle);
166 fn lsm_led_slot_iterator_free(
167 handle: *const c_lsm_led_handle,
168 slot_itr: *const c_lsm_led_slot_itr,
169 );
170 fn lsm_led_slot_iterator_get(
171 handle: *const c_lsm_led_handle,
172 slot_itr: *mut *mut c_lsm_led_slot_itr,
173 lsm_error: *mut *mut c_lsm_error,
174 flags: u64,
175 ) -> c_int;
176
177 fn lsm_led_slot_iterator_reset(
178 handle: *const c_lsm_led_handle,
179 slot_itr: *const c_lsm_led_slot_itr,
180 );
181
182 fn lsm_led_slot_next(
183 handle: *const c_lsm_led_handle,
184 itr: *mut c_lsm_led_slot_itr,
185 ) -> *const c_lsm_led_slot;
186
187 fn lsm_led_slot_status_get(slot: *const c_lsm_led_slot) -> u32;
188
189 fn lsm_led_slot_status_set(
190 handle: *const c_lsm_led_handle,
191 slot: *const c_lsm_led_slot,
192 status: u32,
193 lsm_error: *mut *mut c_lsm_error,
194 flag: u64,
195 ) -> c_int;
196
197 fn lsm_led_slot_id(slot: *const c_lsm_led_slot) -> *const c_char;
198 fn lsm_led_slot_device(slot: *const c_lsm_led_slot) -> *const c_char;
199}
200
201extern "C" {
202 fn free(ptr: *mut c_void);
203}
204
205fn c_char_ptr_to_string(c_str: *const c_char) -> String {
206 let m_str;
207 unsafe {
208 m_str = CStr::from_ptr(c_str);
209 }
210 let str_slice = m_str.to_str().expect("Invalid UTF-8");
211 str_slice.to_owned()
212}
213
214fn lsm_c_error_to_rust(lsm_error: *const c_lsm_error) -> LsmError {
215 let rc;
216 unsafe {
217 if !lsm_error.is_null() {
218 let code = lsm_error_number_get(lsm_error);
219 if code != -1 {
220 let message = lsm_error_message_get(lsm_error);
221
222 if !message.is_null() {
223 rc = lsm_error_code_to_lsm_error(code, c_char_ptr_to_string(message))
224 } else {
225 rc = lsm_error_code_to_lsm_error(
226 code,
227 String::from("no additional information provided"),
228 )
229 }
230
231 assert!(lsm_error_free(lsm_error) == 0);
233 } else {
234 panic!("Invalid lsm_error pointer used for error informational retrieval!");
235 }
236 } else {
237 rc = LsmError::LibBug(String::from("The C lsm error ptr was NULL"));
238 }
239 }
240 rc
241}
242
243fn c_lsm_string_list_to_vec(c_string_list: *const c_lsm_string_list) -> Vec<String> {
244 let mut result_list = Vec::new();
245
246 if !c_string_list.is_null() {
247 unsafe {
248 let num_items = lsm_string_list_size(c_string_list);
249
250 for i in 0..num_items {
251 let disk_path = CStr::from_ptr(lsm_string_list_elem_get(c_string_list, i));
252 result_list.push(disk_path.to_string_lossy().into_owned());
253 }
254 assert!(lsm_string_list_free(c_string_list) == 0);
255 }
256 }
257 result_list
258}
259
260pub fn vpd83_search(vpd83: &str) -> Result<Vec<String>> {
268 let c_search_string = CString::new(vpd83).expect("CString::new failed");
269 let mut disk_paths = std::ptr::null_mut();
270 let mut lsm_error = std::ptr::null_mut();
271
272 unsafe {
273 let rc =
274 lsm_local_disk_vpd83_search(c_search_string.as_ptr(), &mut disk_paths, &mut lsm_error);
275 if rc == 0 {
276 Ok(c_lsm_string_list_to_vec(disk_paths))
277 } else {
278 Err(lsm_c_error_to_rust(lsm_error))
279 }
280 }
281}
282
283pub fn serial_num_get(disk_path: &str) -> Result<String> {
288 let mut serial_num = std::ptr::null_mut();
289 let mut lsm_error = std::ptr::null_mut();
290
291 unsafe {
292 let c_sn = CString::new(disk_path).expect("CString::new failed");
293 let rc = lsm_local_disk_serial_num_get(c_sn.as_ptr(), &mut serial_num, &mut lsm_error);
294
295 if rc == 0 {
296 let sn = CStr::from_ptr(serial_num).to_string_lossy().into_owned();
297 free(serial_num as *mut c_void);
298 Ok(sn)
299 } else {
300 Err(lsm_c_error_to_rust(lsm_error))
301 }
302 }
303}
304
305pub fn vpd83_get(disk_path: &str) -> Result<String> {
307 let mut vpd83 = std::ptr::null_mut();
308 let mut lsm_error = std::ptr::null_mut();
309
310 unsafe {
311 let disk_path = CString::new(disk_path).expect("CString::new failed");
312 let rc = lsm_local_disk_vpd83_get(disk_path.as_ptr(), &mut vpd83, &mut lsm_error);
313
314 if rc == 0 {
315 let vpd = CStr::from_ptr(vpd83).to_string_lossy().into_owned();
316 free(vpd83 as *mut c_void);
317 Ok(vpd)
318 } else {
319 Err(lsm_c_error_to_rust(lsm_error))
320 }
321 }
322}
323
324#[derive(Debug, Copy, Clone, PartialEq, Eq)]
326pub enum HealthStatus {
327 Unknown = -1,
329 Fail = 0,
331 Warn = 1,
333 Good = 2,
335}
336
337impl TryFrom<i32> for HealthStatus {
338 type Error = LsmError;
339
340 fn try_from(value: i32) -> Result<Self> {
341 match value {
342 0 => Ok(HealthStatus::Fail),
343 1 => Ok(HealthStatus::Warn),
344 2 => Ok(HealthStatus::Good),
345 _ => Ok(HealthStatus::Unknown),
346 }
347 }
348}
349
350#[repr(i32)]
352#[derive(Debug, Copy, Clone, PartialEq, Eq)]
353pub enum Rpm {
354 Unknown = -1,
356 NonRotatingMedium = 0,
358 UnknownRotationalSpeed = 1,
360 Rpm(i32),
362}
363
364impl TryFrom<i32> for Rpm {
365 type Error = LsmError;
366
367 fn try_from(value: i32) -> Result<Self> {
368 let rc = match value {
369 -1 => Rpm::Unknown,
370 0 => Rpm::NonRotatingMedium,
371 1 => Rpm::UnknownRotationalSpeed,
372 _ => Rpm::Rpm(value),
373 };
374 Ok(rc)
375 }
376}
377
378pub fn health_get(disk_path: &str) -> Result<HealthStatus> {
380 let mut status: i32 = 0;
381 let mut lsm_error = std::ptr::null_mut();
382
383 unsafe {
384 let disk_path = CString::new(disk_path).expect("CString::new failed");
385 let rc = lsm_local_disk_health_status_get(disk_path.as_ptr(), &mut status, &mut lsm_error);
386
387 if rc == 0 {
388 HealthStatus::try_from(status)
389 } else {
390 Err(lsm_c_error_to_rust(lsm_error))
391 }
392 }
393}
394
395pub fn rpm_get(disk_path: &str) -> Result<Rpm> {
397 let mut rpm: i32 = 0;
398 let mut lsm_error = std::ptr::null_mut();
399
400 unsafe {
401 let disk_path = CString::new(disk_path).expect("CString::new failed");
402 let rc = lsm_local_disk_rpm_get(disk_path.as_ptr(), &mut rpm, &mut lsm_error);
403
404 if rc == 0 {
405 Rpm::try_from(rpm)
406 } else {
407 Err(lsm_c_error_to_rust(lsm_error))
408 }
409 }
410}
411
412pub fn list() -> Result<Vec<String>> {
413 let mut disk_paths = std::ptr::null_mut();
429 let mut lsm_error = std::ptr::null_mut();
430 unsafe {
431 let rc = lsm_local_disk_list(&mut disk_paths, &mut lsm_error);
432 if rc == 0 {
433 Ok(c_lsm_string_list_to_vec(disk_paths))
434 } else {
435 Err(lsm_c_error_to_rust(lsm_error))
436 }
437 }
438}
439
440pub fn link_type_get(disk_path: &str) -> Result<LinkType> {
442 let mut link_type = LinkType::Unknown;
443 let mut lsm_error = std::ptr::null_mut();
444
445 unsafe {
446 let disk_path = CString::new(disk_path).expect("CString::new failed");
447 let rc = lsm_local_disk_link_type_get(disk_path.as_ptr(), &mut link_type, &mut lsm_error);
448
449 if rc == 0 {
450 Ok(link_type)
451 } else {
452 Err(lsm_c_error_to_rust(lsm_error))
453 }
454 }
455}
456
457fn disk_path_led(disk_path: &str, fault_led: bool, on: bool) -> Result<()> {
458 let mut lsm_error = std::ptr::null_mut();
459 unsafe {
460 let dp = CString::new(disk_path).expect("CString::new failed");
461
462 let rc = match (fault_led, on) {
463 (false, true) => lsm_local_disk_ident_led_on(dp.as_ptr(), &mut lsm_error),
464 (false, false) => lsm_local_disk_ident_led_off(dp.as_ptr(), &mut lsm_error),
465 (true, true) => lsm_local_disk_fault_led_on(dp.as_ptr(), &mut lsm_error),
466 (true, false) => lsm_local_disk_fault_led_off(dp.as_ptr(), &mut lsm_error),
467 };
468
469 if rc == 0 {
470 Ok(())
471 } else {
472 Err(lsm_c_error_to_rust(lsm_error))
473 }
474 }
475}
476
477pub fn ident_led_on(disk_path: &str) -> Result<()> {
478 disk_path_led(disk_path, false, true)
493}
494
495pub fn ident_led_off(disk_path: &str) -> Result<()> {
497 disk_path_led(disk_path, false, false)
498}
499
500pub fn fault_led_on(disk_path: &str) -> Result<()> {
502 disk_path_led(disk_path, true, true)
503}
504
505pub fn fault_led_off(disk_path: &str) -> Result<()> {
507 disk_path_led(disk_path, true, false)
508}
509
510pub const LED_STATUS_UNKNOWN: u32 = 0x0000000000000001;
512pub const LED_STATUS_IDENT_ON: u32 = 0x0000000000000002;
514pub const LED_STATUS_IDENT_OFF: u32 = 0x0000000000000004;
516pub const LED_STATUS_IDENT_UNKNOWN: u32 = 0x0000000000000008;
518pub const LED_STATUS_FAULT_ON: u32 = 0x0000000000000010;
520pub const LED_STATUS_FAULT_OFF: u32 = 0x0000000000000020;
522pub const LED_STATUS_FAULT_UNKNOWN: u32 = 0x0000000000000040;
524
525pub fn led_status_get(disk_path: &str) -> Result<u32> {
531 let mut lsm_error = std::ptr::null_mut();
532 let mut led_status = 0;
533 let dp = CString::new(disk_path).expect("CString::new failed");
534
535 unsafe {
536 let rc = lsm_local_disk_led_status_get(dp.as_ptr(), &mut led_status, &mut lsm_error);
537 if rc == 0 {
538 Ok(led_status)
539 } else {
540 Err(lsm_c_error_to_rust(lsm_error))
541 }
542 }
543}
544
545pub fn link_speed_get(disk_path: &str) -> Result<u32> {
547 let mut lsm_error = std::ptr::null_mut();
548 let mut link_speed = 0;
549 let dp = CString::new(disk_path).expect("CString::new failed");
550
551 unsafe {
552 let rc = lsm_local_disk_link_speed_get(dp.as_ptr(), &mut link_speed, &mut lsm_error);
553 if rc == 0 {
554 Ok(link_speed)
555 } else {
556 Err(lsm_c_error_to_rust(lsm_error))
557 }
558 }
559}
560
561fn slot_id_get(slot: *const c_lsm_led_slot) -> String {
562 let id;
563 unsafe {
564 id = lsm_led_slot_id(slot);
565 }
566 assert!(!id.is_null());
567 c_char_ptr_to_string(id)
568}
569
570fn slot_device_get(slot: *const c_lsm_led_slot) -> Option<String> {
571 let device;
572 unsafe {
573 device = lsm_led_slot_device(slot);
574 }
575
576 if device.is_null() {
577 None
578 } else {
579 Some(c_char_ptr_to_string(device))
580 }
581}
582
583pub struct LedSlots {
585 handle: *mut c_lsm_led_handle,
586 itr: *mut c_lsm_led_slot_itr,
587 curr_slot: *const c_lsm_led_slot,
588 curr_id: String,
589}
590
591impl Drop for LedSlots {
592 fn drop(&mut self) {
593 unsafe {
594 lsm_led_slot_iterator_free(self.handle, self.itr);
595 self.itr = std::ptr::null_mut();
596 lsm_led_handle_free(self.handle);
597 self.handle = std::ptr::null_mut();
598 self.curr_slot = std::ptr::null_mut();
599 }
600 }
601}
602
603impl LedSlots {
604 fn find_slot(&mut self, id: &str) -> bool {
605 let mut rc = false;
606 unsafe {
607 if !self.itr.is_null() {
609 let slot = lsm_led_slot_next(self.handle, self.itr);
610 if !slot.is_null() {
611 let slot_id = slot_id_get(slot);
612 if id == slot_id {
613 self.curr_slot = slot;
614 self.curr_id = slot_id;
615 return true;
616 }
617 }
618 }
619
620 lsm_led_slot_iterator_reset(self.handle, self.itr);
621 loop {
622 let slot = lsm_led_slot_next(self.handle, self.itr);
623 if slot.is_null() {
624 break;
625 } else {
626 let slot_id = slot_id_get(slot);
627 if id == slot_id {
628 rc = true;
629 self.curr_slot = slot;
630 self.curr_id = slot_id;
631 break;
632 }
633 }
634 }
635 }
636 rc
637 }
638
639 fn slot_set(&mut self, id: &str) {
640 if self.curr_id != id {
641 assert!(self.find_slot(id));
642 }
643 }
644
645 pub fn new() -> Result<Self> {
647 unsafe {
648 let mut handle = std::ptr::null_mut();
649 let mut itr = std::ptr::null_mut();
650 let mut lsm_error = std::ptr::null_mut();
651
652 let handle_rc = lsm_led_handle_get(&mut handle, 0);
653
654 if handle_rc == 0 {
655 let itr_rc = lsm_led_slot_iterator_get(handle, &mut itr, &mut lsm_error, 0);
656
657 if itr_rc == 0 {
658 Ok(Self {
659 handle,
660 itr,
661 curr_slot: std::ptr::null_mut(),
662 curr_id: String::new(),
663 })
664 } else {
665 lsm_led_handle_free(handle);
667 Err(lsm_c_error_to_rust(lsm_error))
668 }
669 } else {
670 Err(lsm_error_code_to_lsm_error(
671 handle_rc,
672 String::from("LedSlot::new() failed, no additional information!"),
673 ))
674 }
675 }
676 }
677
678 pub fn slots_get(&mut self) -> Vec<LedSlot> {
680 let mut rc = Vec::new();
681
682 unsafe {
683 lsm_led_slot_iterator_reset(self.handle, self.itr);
684
685 loop {
686 let slot = lsm_led_slot_next(self.handle, self.itr);
687 if !slot.is_null() {
688 let entry = LedSlot::new(slot);
689 rc.push(entry);
690 } else {
691 break;
692 }
693 }
694 }
695
696 rc
697 }
698
699 pub fn slot_status_get(&mut self, slot: &LedSlot) -> u32 {
701 self.slot_set(&slot.id());
702 unsafe { lsm_led_slot_status_get(self.curr_slot) }
703 }
704
705 pub fn slot_status_set(&mut self, slot: &LedSlot, state: u32) -> Result<()> {
722 self.slot_set(&slot.id());
723
724 let mut lsm_error = std::ptr::null_mut();
725
726 unsafe {
727 let rc = lsm_led_slot_status_set(self.handle, self.curr_slot, state, &mut lsm_error, 0);
728 if rc == 0 {
729 Ok(())
730 } else {
731 Err(lsm_c_error_to_rust(lsm_error))
732 }
733 }
734 }
735}
736
737pub struct LedSlot {
741 id: String,
743 dev: Option<String>,
745}
746impl LedSlot {
747 fn new(slot: *const c_lsm_led_slot) -> Self {
748 Self {
749 id: slot_id_get(slot),
750 dev: slot_device_get(slot),
751 }
752 }
753
754 pub fn id(&self) -> String {
756 self.id.clone()
757 }
758
759 pub fn device(&self) -> Option<String> {
761 self.dev.clone()
762 }
763}