-
Notifications
You must be signed in to change notification settings - Fork 11
Fcntl_syscall updates #259
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
5775fcd
d1bd972
6dbafda
81dcee4
0b6fd76
477f229
0058a37
0efa0f5
b4d08c0
a343f13
ddbf304
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1898,87 +1898,126 @@ impl Cage { | |
| } | ||
|
|
||
| //------------------------------------FCNTL SYSCALL------------------------------------ | ||
|
|
||
| //fcntl performs operations, like returning or setting file status flags, | ||
| //duplicating a file descriptor, etc., on an open file descriptor | ||
| //it accepts three parameters: fd - an open file descriptor, cmd - an operation to be performed on fd, | ||
| //and arg - an optional argument (whether or not arg is required is determined by cmd) | ||
| //for a successful call, the return value depends on the operation and can be one of: zero, the new file descriptor, | ||
| //value of file descriptor flags, value of status flags, etc. | ||
| //for more detailed description of all the commands and return values, see | ||
| //https://linux.die.net/man/2/fcntl | ||
|
|
||
| pub fn fcntl_syscall(&self, fd: i32, cmd: i32, arg: i32) -> i32 { | ||
| let checkedfd = self.get_filedescriptor(fd).unwrap(); | ||
| let mut unlocked_fd = checkedfd.write(); | ||
| if let Some(filedesc_enum) = &mut *unlocked_fd { | ||
| let flags = match filedesc_enum { | ||
| Epoll(obj) => &mut obj.flags, | ||
| Pipe(obj) => &mut obj.flags, | ||
| Stream(obj) => &mut obj.flags, | ||
| File(obj) => &mut obj.flags, | ||
| Socket(ref mut sockfdobj) => { | ||
| if cmd == F_SETFL && arg >= 0 { | ||
| let sock_tmp = sockfdobj.handle.clone(); | ||
| let mut sockhandle = sock_tmp.write(); | ||
|
|
||
| if let Some(ins) = &mut sockhandle.innersocket { | ||
| let fcntlret; | ||
| if arg & O_NONBLOCK == O_NONBLOCK { | ||
| //set for non-blocking I/O | ||
| fcntlret = ins.set_nonblocking(); | ||
| } else { | ||
| //clear non-blocking I/O | ||
| fcntlret = ins.set_blocking(); | ||
| } | ||
| if fcntlret < 0 { | ||
| match Errno::from_discriminant(interface::get_errno()) { | ||
| Ok(i) => { | ||
| return syscall_error( | ||
| i, | ||
| "fcntl", | ||
| "The libc call to fcntl failed!", | ||
| ); | ||
| //if the provided file descriptor is out of bounds, get_filedescriptor returns Err(), | ||
| //matching on which throws a 'Bad file number' error | ||
| //otherwise, file descriptor table entry is stored in 'checkedfd' | ||
| let fd_table_entry_ptr = self.get_filedescriptor(fd); | ||
| match fd_table_entry_ptr { | ||
| Err(()) => { | ||
| syscall_error(Errno::EBADF, "fcntl", "File descriptor is out of range") | ||
| }, | ||
| Ok(checkedfd) => { | ||
| let mut unlocked_fd = checkedfd.write(); | ||
| //returning a 'Bad file number' error if the file descriptor entry is empty | ||
| //performing the specified command otherwise | ||
| let fd_table_entry = &mut *unlocked_fd; | ||
| match fd_table_entry { | ||
| None => syscall_error(Errno::EBADF, "fcntl", "Invalid file descriptor"), | ||
| Some(filedesc_enum) => { | ||
| //'flags' consists of bitwise-or'd access mode, file creation, and file status flags | ||
| //to retrieve a particular flag, it can bitwise-and'd with 'flags' | ||
| let flags = match filedesc_enum { | ||
| Epoll(obj) => &mut obj.flags, | ||
| Pipe(obj) => &mut obj.flags, | ||
| Stream(obj) => &mut obj.flags, | ||
| File(obj) => &mut obj.flags, | ||
| //not clear why running F_SETFL on Socket type requires special treatment | ||
| Socket(ref mut sockfdobj) => { | ||
| if cmd == F_SETFL && arg >= 0 { | ||
| let sock_tmp = sockfdobj.handle.clone(); | ||
| let mut sockhandle = sock_tmp.write(); | ||
|
|
||
| if let Some(ins) = &mut sockhandle.innersocket { | ||
| let fcntlret; | ||
| if arg & O_NONBLOCK == O_NONBLOCK { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Deep nesting. Is there a way we can avoid this?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No not easily. The rustfmt makes it looks worse than it is.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think clippy will suggest a way to change this pattern: into an
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems fine as it for now but may be part of a later refactor. |
||
| //set non-blocking I/O | ||
| fcntlret = ins.set_nonblocking(); | ||
| } else { | ||
| //set blocking I/O | ||
| fcntlret = ins.set_blocking(); | ||
| } | ||
| if fcntlret < 0 { | ||
| match Errno::from_discriminant(interface::get_errno()) { | ||
| Ok(i) => { | ||
| return syscall_error( | ||
| i, | ||
| "fcntl", | ||
| "The libc call to fcntl failed!", | ||
| ); | ||
| } | ||
| Err(()) => panic!("Unknown errno value from fcntl returned!"), | ||
| }; | ||
| } | ||
| } | ||
| Err(()) => panic!("Unknown errno value from fcntl returned!"), | ||
| }; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| &mut sockfdobj.flags | ||
| } | ||
| }; | ||
| &mut sockfdobj.flags | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove extra whitespace |
||
| } | ||
| }; | ||
|
|
||
| //matching the tuple | ||
| match (cmd, arg) { | ||
| //because the arg parameter is not used in certain commands, it can be anything (..) | ||
| (F_GETFD, ..) => *flags & O_CLOEXEC, | ||
| // set the flags but make sure that the flags are valid | ||
| (F_SETFD, arg) if arg >= 0 => { | ||
| if arg & O_CLOEXEC != 0 { | ||
| *flags |= O_CLOEXEC; | ||
| } else { | ||
| *flags &= !O_CLOEXEC; | ||
| //matching the tuple | ||
| match (cmd, arg) { | ||
| //because the arg parameter is not used in certain commands, it can be anything (..) | ||
| //F_GETFD returns file descriptor flags only, meaning that access mode flags | ||
| //and file status flags are excluded | ||
| //F_SETFD is used to set file descriptor flags only, meaning that any changes to access mode flags | ||
| //or file status flags should be ignored | ||
| //currently, O_CLOEXEC is the only defined file descriptor flag, thus only this flag is | ||
| //masked when using F_GETFD or F_SETFD | ||
| (F_GETFD, ..) => *flags & O_CLOEXEC, | ||
| (F_SETFD, arg) if arg >= 0 => { | ||
| if arg & O_CLOEXEC != 0 { | ||
| //if O_CLOEXEC flag is set to 1 in 'arg', 'flags' is updated by setting its O_CLOEXEC bit to 1 | ||
| *flags |= O_CLOEXEC; | ||
| } else { | ||
| //if O_CLOEXEC flag is set to 0 in 'arg', 'flags' is updated by setting its O_CLOEXEC bit to 0 | ||
| *flags &= !O_CLOEXEC; | ||
| } | ||
| 0 | ||
| } | ||
| //F_GETFL should return file access mode and file status flags, which means that | ||
| //file creation flags should be masked out | ||
| (F_GETFL, ..) => { | ||
| *flags & !(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC) | ||
| } | ||
| //F_SETFL is used to set file status flags, thus any changes to file access mode and file | ||
| //creation flags should be ignored (see F_SETFL command in the man page for fcntl for the reference) | ||
| (F_SETFL, arg) if arg >= 0 => { | ||
| //valid changes are extracted by ignoring changes to file access mode and file creation flags | ||
| let valid_changes = arg & !(O_RDWRFLAGS | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); | ||
| //access mode and creation flags are extracted and other flags are set to 0 to update them | ||
| let acc_and_creation_flags = *flags & (O_RDWRFLAGS | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); | ||
| //valid changes are combined with the old file access mode and file creation flags | ||
| *flags = valid_changes | acc_and_creation_flags; | ||
| 0 | ||
| } | ||
| (F_DUPFD, arg) if arg >= 0 => self._dup2_helper(&filedesc_enum, arg, false), | ||
| //TO DO: F_GETOWN and F_SETOWN commands are not implemented yet | ||
| (F_GETOWN, ..) => { | ||
| 0 | ||
| } | ||
| (F_SETOWN, arg) if arg >= 0 => { | ||
| 0 | ||
| } | ||
| _ => { | ||
| let err_msg = format!("Arguments pair ({}, {}) does not match implemented parameters", cmd, arg); | ||
| syscall_error(Errno::EINVAL, "fcntl", &err_msg) | ||
| }, | ||
| } | ||
| } | ||
| 0 | ||
| } | ||
| (F_GETFL, ..) => { | ||
| //for get, we just need to return the flags | ||
| *flags & !O_CLOEXEC | ||
| } | ||
| (F_SETFL, arg) if arg >= 0 => { | ||
| *flags |= arg; | ||
| 0 | ||
| } | ||
| (F_DUPFD, arg) if arg >= 0 => self._dup2_helper(&filedesc_enum, arg, false), | ||
| //TO DO: implement. this one is saying get the signals | ||
| (F_GETOWN, ..) => { | ||
| 0 //TO DO: traditional SIGIO behavior | ||
| } | ||
| (F_SETOWN, arg) if arg >= 0 => { | ||
| 0 //this would return the PID if positive and the process group if negative, | ||
| //either way do nothing and return success | ||
| } | ||
| _ => syscall_error( | ||
| Errno::EINVAL, | ||
| "fcntl", | ||
| "Arguments provided do not match implemented parameters", | ||
| ), | ||
| } | ||
| } else { | ||
| syscall_error(Errno::EBADF, "fcntl", "Invalid file descriptor") | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
@yashaswi2000 , do you want to have the rustdoc changes be done in these edits or a different set of PRs? I do think that for new PRs, we likely should include them...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will refactor these first 3 PRs. and any new ones coming in will follow the template I will share with them.