How to Use Nix's Ioctl

How to use nix's ioctl?

There is some example usage in rust-spidev. I will try to apply that to your code.

TUNSETIFF is defined as:

#define TUNSETIFF     _IOW('T', 202, int)

That would be this in Rust using nix:

const TUN_IOC_MAGIC: u8 = 'T' as u8;
const TUN_IOC_SET_IFF: u8 = 202;
ioctl!(write tun_set_iff with TUN_IOC_MAGIC, TUN_IOC_SET_IFF; u32);

The above macro will define the function, which you can call like this:

let err = unsafe { tun_set_iff(fd, ifr) }; // assuming ifr is an u32

How to use ioctl + nix macros to get a variable size buffer

Now that Digikata has thoughtfully provided enough code to drive the program...

Am I using the ioctl_read_buf macro incorrectly?

I'd say that using it at all is incorrect here. You don't want to read an array of data, you want to read a single instance of a specific type. That's what ioctl_read! is for.

We define a repr(C) struct that mimics the C definition. This ensures that important details like alignment, padding, field ordering, etc., all match one-to-one with the code we are calling.

We can then construct an uninitialized instance of this struct and pass it to the newly-defined function.

use libc; // 0.2.66
use nix::ioctl_read; // 0.16.1
use std::{
fs::OpenOptions,
mem::MaybeUninit,
os::unix::{fs::OpenOptionsExt, io::AsRawFd},
};

const HID_MAX_DESCRIPTOR_SIZE: usize = 4096;

#[repr(C)]
pub struct hidraw_report_descriptor {
size: u32,
value: [u8; HID_MAX_DESCRIPTOR_SIZE],
}

ioctl_read!(hid_read_sz, b'H', 0x01, libc::c_int);
ioctl_read!(hid_read_descr, b'H', 0x02, hidraw_report_descriptor);

fn main() -> Result<(), Box<dyn std::error::Error>> {
let file = OpenOptions::new()
.read(true)
.write(true)
.custom_flags(libc::O_NONBLOCK)
.open("/dev/hidraw0")?;

unsafe {
let fd = file.as_raw_fd();

let mut size = 0;
hid_read_sz(fd, &mut size)?;
println!("{}", size);

let mut desc_raw = MaybeUninit::<hidraw_report_descriptor>::uninit();
(*desc_raw.as_mut_ptr()).size = size as u32;
hid_read_descr(file.as_raw_fd(), desc_raw.as_mut_ptr())?;
let desc_raw = desc_raw.assume_init();
let data = &desc_raw.value[..desc_raw.size as usize];
println!("{:02x?}", data);
}

Ok(())
}

How to call ioctl in Rust? And interface the Linux tun driver

You can find ioctl in nix, which contains convenience wrapper of *nix functionalities.

How can I call ioctl for interface list, or other ioctl stuff, on Free Pascal?

Does BaseUnix.FpIOCtl meet your use case? Have a look at the BaseUnix documentation. I found an example of using it here (reposted below).

program testrpi;

{$mode objfpc}{$H+}

uses
baseUnix,
classes,
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
sysutils;

const
I2C_SLAVE = 1795;

var
buf : packed array [0..1] of char;
c : char;
devPath : string = '/dev/i2c-1';
handle : Cint;
iDevAddr : Cint = $04;

begin

try
handle := fpopen(devPath,O_RDWR);
fpIOCtl(handle, I2C_SLAVE, pointer(iDevAddr));
except
writeln('Error initalizing i2c');
halt;
end;

while true do begin

write('Enter digit 1-9:');
readln(c);
if (not(c in ['1'..'9'])) then begin
writeln('oops - try again');
continue;
end;
buf[0] := chr(ord(c) - ord('0'));

try
fpwrite(handle, buf, 1);
except
writeln('Error writing');
halt;
end; //try

buf[0] := #99;
sleep(10);

try
fpread(handle, buf, 1);
except
writeln('Error reading');
halt;
end; //try

writeln('buf=', ord(buf[0]));
end; //while

fpclose(handle);

end.

How are ioctl() and/or fcntl() used for writing a non-blocking socket?

You use one or the other to set O_NONBLOCK. Surely you already discovered that?

What happens to the invocation of system call when a process is killed (*nix)?

What happens in operating system kernel (Linux 2+/FreeBSD7+/OSX) when
a process is being killed (SIGKILL) while it is executing a system
call?

A process executes a system call in the context of kernel mode. At this time if kernel receives any interrupt(signal comes under software interrupt), it would check out for the priority of that particular interrupt. Software interrupt has least priority among all type of interrupt and hence it would continue to execute until it finished the critical path execution. At this point kernel would store its context and would determine the reason and priority of interrupt and service the interrupt(which is in this case is to terminate/kill the program).

However these concepts are bit complicated and may vary on different system. You may want to refer the great book "The Design Of UNIX Operating System" By Maurice J Bach which describes these concepts and the implementation in detailed way.

In particular: does every single system call know how to clean-up
itself when process termination is imminent?

Yes, As system calls gets executed in the context of kernel mode on behalf of a process.
So they always do have the logic to clean-up while process has started to abort/terminate. If user mode program terminates due to unexpected reason,kernel ensures that it clean up all the resources of that particular process. This is the great thing about kernel.

inappropriate ioctl for device

Most likely it means that the open didn't fail.

When Perl opens a file, it checks whether or not the file is a TTY (so that it can answer the -T $fh filetest operator) by issuing the TCGETS ioctl against it. If the file is a regular file and not a tty, the ioctl fails and sets errno to ENOTTY (string value: "Inappropriate ioctl for device"). As ysth says, the most common reason for seeing an unexpected value in $! is checking it when it's not valid -- that is, anywhere other than immediately after a syscall failed, so testing the result codes of your operations is critically important.

If open actually did return false for you, and you found ENOTTY in $! then I would consider this a small bug (giving a useless value of $!) but I would also be very curious as to how it happened. Code and/or truss output would be nifty.



Related Topics



Leave a reply



Submit