1use std::fs::{ File, read_dir, read_link };
2use std::mem::zeroed;
3use std::os::unix::io::AsRawFd;
4use std::io::{ BufReader, BufRead, Error };
5
6extern crate libc;
7use libc::{ c_int, ioctl };
8
9extern crate kstat;
10use kstat::KstatReader;
11use kstat::kstat_named::KstatNamedData;
12
13
14const DKIOCREMOVABLE: i32 = 1040;
15const DKIOCGMEDIAINFO: i32 = 1066;
16const DKIOCINFO: i32 = 1027;
17
18pub type ULonglongT = ::std::os::raw::c_ulonglong;
19pub type DiskaddrT = ULonglongT;
20pub type UChar = ::std::os::raw::c_uchar;
21pub type UShortT = ::std::os::raw::c_ushort;
22pub type UIntT = ::std::os::raw::c_uint;
23
24
25#[repr(C)]
26#[derive(Debug, Copy, Clone)]
27pub struct DkMinfo {
28 pub dki_media_type: UIntT,
29 pub dki_lbsize: UIntT,
30 pub dki_capacity: DiskaddrT,
31}
32
33#[repr(C)]
34#[derive(Debug, Copy, Clone)]
35pub struct DkCinfo {
36 pub dki_cname: [::std::os::raw::c_char; 16usize],
37 pub dki_ctype: UShortT,
38 pub dki_flags: UShortT,
39 pub dki_cnum: UShortT,
40 pub dki_addr: UIntT,
41 pub dki_space: UIntT,
42 pub dki_prio: UIntT,
43 pub dki_vec: UIntT,
44 pub dki_dname: [::std::os::raw::c_char; 16usize],
45 pub dki_unit: UIntT,
46 pub dki_slave: UIntT,
47 pub dki_partition: UShortT,
48 pub dki_maxtransfer: UShortT,
49}
50
51pub fn get_removable(fd: c_int) -> i64 {
52 let mut removable = 0;
53 let res = unsafe { ioctl(fd, DKIOCREMOVABLE, &mut removable) };
54 if res == -1 {
55 panic!("DKIOCREMOVABLE err")
56 }
57 removable
58}
59
60pub fn get_ctype(fd: c_int) -> String {
61 let mut dkinfo:DkCinfo = unsafe { zeroed() };
62 let mut ctype:String = String::new();
63 let res = unsafe { ioctl(fd, DKIOCINFO, &mut dkinfo) };
64 if res == -1 {
65 panic!("DKIOCINFO err");
66 }
67 match dkinfo.dki_ctype {
68 20 => ctype.push_str("ATA"),
69 13 => ctype.push_str("SCSI"),
70 _ => ctype.push_str("UNKNOWN"),
71 }
72 ctype
73}
74
75pub fn get_media(fd: c_int) -> f64 {
76 let mut media: DkMinfo = unsafe { zeroed() };
77 let res = unsafe { ioctl(fd, DKIOCGMEDIAINFO, &mut media) };
78 if res == -1 {
79 panic!("DKIOMEDIA err")
80 }
81 let size = ((media.dki_lbsize as u64 * media.dki_capacity) as f64) / 1024.0 / 1024.0 / 1024.0;
82 size
83}
84
85fn format_ks(m: &KstatNamedData) -> String {
86 let s = format!("{:?}!", m);
87 let tokens: Vec<_> = s.split('"').collect();
88 tokens[1].to_string()
89}
90
91fn get_kstat(sd: &str, data: &str) -> String {
92 let mut kstat_val:String = String::new();
93 let dkerr = format!("{},err", sd);
94 let reader = KstatReader::new(None, None, Some(dkerr), None)
95 .expect("failed to create kstat reader");
96 let stats = reader.read().expect("failed to read kstats");
97 for stat in stats {
98 kstat_val = format_ks(&stat.data[data]);
99 }
100 kstat_val
101}
102
103fn print_disk(path: &str, fname: File, disk: &str) {
104 let ctype = get_ctype(fname.as_raw_fd());
105 let res = get_removable(fname.as_raw_fd());
106 if res == 0 {
107 let dksize = get_media(fname.as_raw_fd());
108 let sympath = read_link(&path).unwrap();
109 let devpath = sympath.into_os_string().into_string().unwrap();
110 let tokens: Vec<&str> = devpath.split("/").collect();
111 let sdpart = tokens[tokens.len()-1];
112 let sdnum: Vec<&str> = sdpart.split(":").collect();
113 let pathinst = File::open("/etc/path_to_inst").unwrap();
114 let file = BufReader::new(&pathinst);
115 for line in file.lines() {
116 let l = line.unwrap();
117 if l.contains(sdnum[0]) && l.contains(tokens[tokens.len()-2]) {
118 let sdtok: Vec<&str> = l.split(" ").collect();
119 let sd = format!("sd{}", sdtok[sdtok.len()-2]);
120 let serial = get_kstat(&sd, "Serial No");
121 let product = get_kstat(&sd, "Product");
122 let vendor = get_kstat(&sd, "Vendor");
123 println!("{: <7} {: <23} {: <8} {: <16} {: <20} {:.2?} GiB",
124 ctype, disk, vendor, product, serial, dksize);
125 }
126 }
127 }
128}
129
130pub fn get_disks() -> Result<(), Box<Error>> {
131 let dir = "/dev/rdsk";
132 println!("TYPE DISK VID PID SERIAL SIZE");
133 for entry in read_dir(dir).unwrap() {
134 let post_path = entry.unwrap().path();
135 let fname = post_path.file_name().unwrap().to_str().unwrap();
136 if fname.ends_with("p0") {
137 let mut disk = String::from(fname);
138 let len = disk.len();
139 disk.truncate(len - 2);
140 let path = ["/dev/rdsk", fname].join("/");
141 let _rawfd = match File::open(&path) {
142 Ok(rawfd) => print_disk(&path, rawfd, &disk),
143 Err(_error) => (),
144 };
145 }
146 }
147 Ok(())
148}
149