os/kernel/syscall/
ioctl.rs

1//! ioctl 系统调用实现
2//!
3//! ioctl (input/output control) 是一个多功能的系统调用,用于设备特定的控制操作。
4
5use crate::arch::trap::SumGuard;
6use crate::kernel::current_task;
7use crate::uapi::errno::{EBADF, EINVAL, ENOTTY, EOPNOTSUPP};
8use crate::uapi::ioctl::*;
9use crate::vfs::FsError;
10use crate::{earlyprintln, pr_debug, pr_err, pr_warn};
11
12/// ioctl - 设备特定的输入/输出控制
13///
14/// # 参数
15/// - `fd`: 文件描述符
16/// - `request`: ioctl 请求码(由 _IO, _IOR, _IOW, _IOWR 宏构造)
17/// - `arg`: 参数指针(根据 request 类型解释)
18///
19/// # 返回值
20/// - 成功: 返回 0 或设备特定的值
21/// - 失败: 返回 -errno
22///
23/// # 支持的操作
24///
25/// ## 通用文件操作
26/// - `FIONBIO` - 设置非阻塞模式
27/// - `FIONREAD` - 获取可读字节数
28/// - `FIOASYNC` - 设置异步 I/O
29///
30/// ## 终端操作
31/// - `TIOCGWINSZ` - 获取终端窗口大小
32/// - `TIOCSWINSZ` - 设置终端窗口大小
33/// - `TCGETS` - 获取终端属性
34/// - `TCSETS` - 设置终端属性
35///
36/// ## 网络操作
37/// - `SIOCGIFCONF` - 获取网络接口列表
38/// - `SIOCGIFADDR` - 获取接口地址
39/// - `SIOCGIFFLAGS` - 获取接口标志
40/// - 等等(详见 uapi/ioctl.rs)
41///
42/// # 注意
43/// - 大部分 ioctl 操作需要相应的设备驱动程序支持
44/// - 无效的 request 码会返回 ENOTTY
45pub fn ioctl(fd: i32, request: u32, arg: usize) -> isize {
46    pr_debug!(
47        "ioctl: fd={}, request={:#x} ({}), arg={:#x}",
48        fd,
49        request,
50        request,
51        arg
52    );
53
54    // 参数验证
55    if fd < 0 {
56        pr_err!("ioctl: invalid fd {}", fd);
57        return -EBADF as isize;
58    }
59
60    // 获取文件对象
61    let task = current_task();
62    let file = {
63        let task_lock = task.lock();
64        match task_lock.fd_table.get(fd as usize) {
65            Ok(f) => f,
66            Err(_) => {
67                pr_err!("ioctl: fd {} not found", fd);
68                return -EBADF as isize;
69            }
70        }
71    };
72
73    // 根据 request 类型分发处理
74    let result = match request {
75        //  通用文件 I/O 控制
76        FIONBIO => handle_fionbio(&file, arg),
77        FIONREAD => handle_fionread(&file, arg),
78        FIOASYNC => handle_fioasync(&file, arg),
79
80        //  终端控制 - 委托给文件对象的 ioctl 方法
81        TIOCGWINSZ | TIOCSWINSZ | TCGETS | TCSETS | TCSETSW | TCSETSF => {
82            match file.ioctl(request, arg) {
83                Ok(ret) => ret,
84                Err(FsError::NotSupported) => {
85                    pr_warn!(
86                        "ioctl: fd={}, terminal request {:#x} ({}) not supported by file type",
87                        fd,
88                        request,
89                        request
90                    );
91                    -ENOTTY as isize
92                }
93                Err(e) => fs_error_to_errno(e),
94            }
95        }
96
97        //  终端进程组控制 - 读取/设置任务的 pgid
98        TIOCGPGRP => handle_tiocgpgrp(&task, arg),
99        TIOCSPGRP => handle_tiocspgrp(&task, arg),
100
101        //  控制终端设置
102        TIOCSCTTY => handle_tiocsctty(&file, arg),
103
104        //  虚拟终端查询
105        VT_OPENQRY => handle_vt_openqry(arg),
106
107        //  网络 Socket 控制
108        SIOCGIFCONF => handle_siocgifconf(arg),
109        SIOCGIFADDR | SIOCSIFADDR | SIOCGIFFLAGS | SIOCSIFFLAGS | SIOCGIFNETMASK
110        | SIOCSIFNETMASK | SIOCGIFMTU | SIOCSIFMTU | SIOCGIFHWADDR | SIOCSIFHWADDR
111        | SIOCGIFINDEX => handle_ifreq(&file, request, arg),
112
113        //  设备特定
114        // 尝试委托给文件对象的 ioctl 方法
115        _ => {
116            pr_debug!("ioctl: delegating request {:#x} to file object", request);
117            match file.ioctl(request, arg) {
118                Ok(ret) => ret,
119                Err(FsError::NotSupported) => {
120                    pr_warn!(
121                        "ioctl: unsupported request {:#x} (type={:#x}, nr={}, size={})",
122                        request,
123                        _IOC_TYPE(request),
124                        _IOC_NR(request),
125                        _IOC_SIZE(request)
126                    );
127                    -ENOTTY as isize
128                }
129                Err(e) => {
130                    pr_err!("ioctl: file ioctl failed: {:?}", e);
131                    fs_error_to_errno(e)
132                }
133            }
134        }
135    };
136
137    pr_debug!(
138        "ioctl: fd={}, request={:#x} => result={}",
139        fd,
140        request,
141        result
142    );
143    result
144}
145
146//  通用文件 I/O 控制处理函数
147
148/// FIONBIO - 设置/清除非阻塞 I/O 标志
149fn handle_fionbio(file: &alloc::sync::Arc<dyn crate::vfs::File>, arg: usize) -> isize {
150    unsafe {
151        let _guard = SumGuard::new();
152        let value_ptr = arg as *const i32;
153        if value_ptr.is_null() {
154            return -EINVAL as isize;
155        }
156
157        let value = core::ptr::read_volatile(value_ptr);
158
159        // 设置文件的 O_NONBLOCK 标志
160        let mut flags = file.flags();
161        if value != 0 {
162            flags |= crate::uapi::fcntl::OpenFlags::O_NONBLOCK;
163        } else {
164            flags &= !crate::uapi::fcntl::OpenFlags::O_NONBLOCK;
165        }
166
167        match file.set_status_flags(flags) {
168            Ok(_) => 0,
169            Err(e) => {
170                pr_warn!("ioctl: FIONBIO failed: {:?}", e);
171                -EOPNOTSUPP as isize
172            }
173        }
174    }
175}
176
177/// FIONREAD - 获取可读字节数
178fn handle_fionread(file: &alloc::sync::Arc<dyn crate::vfs::File>, arg: usize) -> isize {
179    unsafe {
180        let _guard = SumGuard::new();
181        let value_ptr = arg as *mut i32;
182        if value_ptr.is_null() {
183            return -EINVAL as isize;
184        }
185
186        // 对于普通文件,可读字节数 = 文件大小 - 当前偏移量
187        let available = match file.metadata() {
188            Ok(meta) => {
189                let size = meta.size;
190                let offset = file.offset();
191                if size > offset {
192                    (size - offset) as i32
193                } else {
194                    0
195                }
196            }
197            Err(_) => {
198                // 对于不支持 metadata 的设备,返回 0
199                0
200            }
201        };
202
203        core::ptr::write_volatile(value_ptr, available);
204        0
205    }
206}
207
208/// FIOASYNC - 设置/清除异步 I/O 通知
209fn handle_fioasync(file: &alloc::sync::Arc<dyn crate::vfs::File>, arg: usize) -> isize {
210    unsafe {
211        let _guard = SumGuard::new();
212        let value_ptr = arg as *const i32;
213        if value_ptr.is_null() {
214            return -EINVAL as isize;
215        }
216
217        let _value = core::ptr::read_volatile(value_ptr);
218
219        // TODO: 实现异步 I/O 支持
220        pr_warn!("ioctl: FIOASYNC not yet implemented");
221        -EOPNOTSUPP as isize
222    }
223}
224
225//  终端控制处理函数
226
227/// TIOCGPGRP - 获取终端前台进程组 ID
228fn handle_tiocgpgrp(
229    task: &alloc::sync::Arc<crate::sync::SpinLock<crate::kernel::task::TaskStruct>>,
230    arg: usize,
231) -> isize {
232    if arg == 0 {
233        return -EINVAL as isize;
234    }
235
236    let pgid = task.lock().pgid as i32;
237    earlyprintln!("ioctl: TIOCGPGRP writing pgid={} to {:#x}", pgid, arg);
238
239    unsafe {
240        crate::util::user_buffer::write_to_user(arg as *mut i32, pgid);
241    }
242
243    earlyprintln!("ioctl: TIOCGPGRP completed");
244    0
245}
246
247/// TIOCSPGRP - 设置终端前台进程组 ID
248fn handle_tiocspgrp(
249    task: &alloc::sync::Arc<crate::sync::SpinLock<crate::kernel::task::TaskStruct>>,
250    arg: usize,
251) -> isize {
252    unsafe {
253        let _guard = SumGuard::new();
254        let pid_ptr = arg as *const i32;
255        if pid_ptr.is_null() {
256            return -EINVAL as isize;
257        }
258
259        let pgid = core::ptr::read_volatile(pid_ptr);
260
261        // 设置当前任务的进程组 ID
262        task.lock().pgid = pgid as u32;
263
264        earlyprintln!("ioctl: TIOCSPGRP set pgid={}", pgid);
265        0
266    }
267}
268
269/// TIOCSCTTY - 设置控制终端
270///
271/// 这个 ioctl 用于使当前终端成为调用进程的控制终端。
272/// busybox init 在启动时会调用这个函数。
273/// 目前我们只是简单返回成功,因为我们还没有完整的会话管理。
274fn handle_tiocsctty(_file: &alloc::sync::Arc<dyn crate::vfs::File>, _arg: usize) -> isize {
275    // TODO: 实现完整的控制终端管理
276    // 目前只是返回成功,让 init 可以继续运行
277    earlyprintln!("ioctl: TIOCSCTTY accepted (not fully implemented)");
278    0
279}
280
281/// VT_OPENQRY - 查询可用的虚拟终端
282///
283/// 这个 ioctl 用于查找第一个未打开的虚拟终端号。
284/// 对于不支持虚拟终端的系统,返回 ENOTTY 是合理的。
285fn handle_vt_openqry(arg: usize) -> isize {
286    if arg == 0 {
287        return -EINVAL as isize;
288    }
289
290    // 对于不支持虚拟终端的系统,返回 ENOTTY
291    earlyprintln!("ioctl: VT_OPENQRY not supported (no VT subsystem)");
292    -ENOTTY as isize
293}
294
295//  网络控制处理函数
296
297/// SIOCGIFCONF - 获取网络接口列表
298fn handle_siocgifconf(arg: usize) -> isize {
299    unsafe {
300        let _guard = SumGuard::new();
301        let ifconf_ptr = arg as *mut Ifconf;
302        if ifconf_ptr.is_null() {
303            return -EINVAL as isize;
304        }
305
306        // 读取 ifconf 结构
307        let ifconf = core::ptr::read_volatile(ifconf_ptr);
308
309        // 先清零原结构体,避免泄露内核栈数据
310        core::ptr::write_bytes(ifconf_ptr, 0, 1);
311
312        // TODO: 填充实际的网络接口列表
313        // 目前返回空列表
314        let mut new_ifconf = ifconf;
315        new_ifconf.ifc_len = 0;
316        core::ptr::write_volatile(ifconf_ptr, new_ifconf);
317
318        earlyprintln!("ioctl: SIOCGIFCONF returned 0 interfaces");
319        0
320    }
321}
322
323/// 处理网络接口请求(ifreq 结构)
324fn handle_ifreq(_file: &alloc::sync::Arc<dyn crate::vfs::File>, request: u32, arg: usize) -> isize {
325    unsafe {
326        let _guard = SumGuard::new();
327        let ifreq_ptr = arg as *mut Ifreq;
328        if ifreq_ptr.is_null() {
329            return -EINVAL as isize;
330        }
331
332        let _ifreq = core::ptr::read_volatile(ifreq_ptr);
333
334        // TODO: 实现实际的网络接口操作
335        match request {
336            SIOCGIFADDR | SIOCGIFFLAGS | SIOCGIFNETMASK | SIOCGIFMTU | SIOCGIFHWADDR
337            | SIOCGIFINDEX => {
338                earlyprintln!("ioctl: network get request {:#x} not implemented", request);
339                -EOPNOTSUPP as isize
340            }
341            SIOCSIFADDR | SIOCSIFFLAGS | SIOCSIFNETMASK | SIOCSIFMTU | SIOCSIFHWADDR => {
342                earlyprintln!("ioctl: network set request {:#x} not implemented", request);
343                -EOPNOTSUPP as isize
344            }
345            _ => -EINVAL as isize,
346        }
347    }
348}
349
350//  辅助函数
351
352/// 将 VFS 错误转换为 errno
353fn fs_error_to_errno(err: FsError) -> isize {
354    match err {
355        FsError::NotSupported => -EOPNOTSUPP as isize,
356        FsError::InvalidArgument => -EINVAL as isize,
357        FsError::NotFound => -crate::uapi::errno::ENOENT as isize,
358        FsError::PermissionDenied => -crate::uapi::errno::EACCES as isize,
359        FsError::AlreadyExists => -crate::uapi::errno::EEXIST as isize,
360        FsError::IoError => -crate::uapi::errno::EIO as isize,
361        _ => -crate::uapi::errno::EIO as isize,
362    }
363}