1 use super::arch::*; 2 use super::data::{Map, SigAction, Stat, StatVfs, TimeSpec}; 3 use super::error::Result; 4 use super::flag::*; 5 use super::number::*; 6 7 use core::{mem, ptr}; 8 9 // Signal restorer 10 extern "C" fn restorer() -> ! { 11 sigreturn().unwrap(); 12 unreachable!(); 13 } 14 15 /// Change the process's working directory 16 /// 17 /// This function will attempt to set the process's working directory to `path`, which can be 18 /// either a relative, scheme relative, or absolute path. 19 /// 20 /// On success, `Ok(0)` will be returned. On error, one of the following errors will be returned. 21 /// 22 /// # Errors 23 /// 24 /// * `EACCES` - permission is denied for one of the components of `path`, or `path` 25 /// * `EFAULT` - `path` does not point to the process's addressible memory 26 /// * `EIO` - an I/O error occurred 27 /// * `ENOENT` - `path` does not exit 28 /// * `ENOTDIR` - `path` is not a directory 29 pub fn chdir<T: AsRef<str>>(path: T) -> Result<usize> { 30 unsafe { syscall2(SYS_CHDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) } 31 } 32 33 #[deprecated( 34 since = "0.1.55", 35 note = "use fchmod instead" 36 )] 37 pub fn chmod<T: AsRef<str>>(path: T, mode: usize) -> Result<usize> { 38 unsafe { syscall3(SYS_CHMOD, path.as_ref().as_ptr() as usize, path.as_ref().len(), mode) } 39 } 40 41 /// Produce a fork of the current process, or a new process thread 42 pub unsafe fn clone(flags: CloneFlags) -> Result<usize> { 43 syscall1(SYS_CLONE, flags.bits()) 44 } 45 46 /// Close a file 47 pub fn close(fd: usize) -> Result<usize> { 48 unsafe { syscall1(SYS_CLOSE, fd) } 49 } 50 51 /// Get the current system time 52 pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result<usize> { 53 unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) } 54 } 55 56 /// Copy and transform a file descriptor 57 pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> { 58 unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) } 59 } 60 61 /// Copy and transform a file descriptor 62 pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result<usize> { 63 unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) } 64 } 65 66 /// Exit the current process 67 pub fn exit(status: usize) -> Result<usize> { 68 unsafe { syscall1(SYS_EXIT, status) } 69 } 70 71 /// Change file permissions 72 pub fn fchmod(fd: usize, mode: u16) -> Result<usize> { 73 unsafe { syscall2(SYS_FCHMOD, fd, mode as usize) } 74 75 } 76 77 /// Change file ownership 78 pub fn fchown(fd: usize, uid: u32, gid: u32) -> Result<usize> { 79 unsafe { syscall3(SYS_FCHOWN, fd, uid as usize, gid as usize) } 80 81 } 82 83 /// Change file descriptor flags 84 pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result<usize> { 85 unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) } 86 } 87 88 /// Replace the current process with a new executable 89 pub fn fexec(fd: usize, args: &[[usize; 2]], vars: &[[usize; 2]]) -> Result<usize> { 90 unsafe { syscall5(SYS_FEXEC, fd, args.as_ptr() as usize, args.len(), vars.as_ptr() as usize, vars.len()) } 91 } 92 93 /// Map a file into memory, but with the ability to set the address to map into, either as a hint 94 /// or as a requirement of the map. 95 /// 96 /// # Errors 97 /// `EACCES` - the file descriptor was not open for reading 98 /// `EBADF` - if the file descriptor was invalid 99 /// `ENODEV` - mmapping was not supported 100 /// `EINVAL` - invalid combination of flags 101 /// `EEXIST` - if [`MapFlags::MAP_FIXED`] was set, and the address specified was already in use. 102 /// 103 pub unsafe fn fmap(fd: usize, map: &Map) -> Result<usize> { 104 syscall3(SYS_FMAP, fd, map as *const Map as usize, mem::size_of::<Map>()) 105 } 106 107 /// Unmap whole (or partial) continous memory-mapped files 108 pub unsafe fn funmap(addr: usize, len: usize) -> Result<usize> { 109 syscall2(SYS_FUNMAP, addr, len) 110 } 111 112 /// Retrieve the canonical path of a file 113 pub fn fpath(fd: usize, buf: &mut [u8]) -> Result<usize> { 114 unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) } 115 } 116 117 /// Rename a file 118 pub fn frename<T: AsRef<str>>(fd: usize, path: T) -> Result<usize> { 119 unsafe { syscall3(SYS_FRENAME, fd, path.as_ref().as_ptr() as usize, path.as_ref().len()) } 120 } 121 122 /// Get metadata about a file 123 pub fn fstat(fd: usize, stat: &mut Stat) -> Result<usize> { 124 unsafe { syscall3(SYS_FSTAT, fd, stat as *mut Stat as usize, mem::size_of::<Stat>()) } 125 } 126 127 /// Get metadata about a filesystem 128 pub fn fstatvfs(fd: usize, stat: &mut StatVfs) -> Result<usize> { 129 unsafe { syscall3(SYS_FSTATVFS, fd, stat as *mut StatVfs as usize, mem::size_of::<StatVfs>()) } 130 } 131 132 /// Sync a file descriptor to its underlying medium 133 pub fn fsync(fd: usize) -> Result<usize> { 134 unsafe { syscall1(SYS_FSYNC, fd) } 135 } 136 137 /// Truncate or extend a file to a specified length 138 pub fn ftruncate(fd: usize, len: usize) -> Result<usize> { 139 unsafe { syscall2(SYS_FTRUNCATE, fd, len) } 140 } 141 142 // Change modify and/or access times 143 pub fn futimens(fd: usize, times: &[TimeSpec]) -> Result<usize> { 144 unsafe { syscall3(SYS_FUTIMENS, fd, times.as_ptr() as usize, times.len() * mem::size_of::<TimeSpec>()) } 145 } 146 147 /// Fast userspace mutex 148 pub unsafe fn futex(addr: *mut i32, op: usize, val: i32, val2: usize, addr2: *mut i32) 149 -> Result<usize> { 150 syscall5(SYS_FUTEX, addr as usize, op, (val as isize) as usize, val2, addr2 as usize) 151 } 152 153 /// Get the current working directory 154 pub fn getcwd(buf: &mut [u8]) -> Result<usize> { 155 unsafe { syscall2(SYS_GETCWD, buf.as_mut_ptr() as usize, buf.len()) } 156 } 157 158 /// Get the effective group ID 159 pub fn getegid() -> Result<usize> { 160 unsafe { syscall0(SYS_GETEGID) } 161 } 162 163 /// Get the effective namespace 164 pub fn getens() -> Result<usize> { 165 unsafe { syscall0(SYS_GETENS) } 166 } 167 168 /// Get the effective user ID 169 pub fn geteuid() -> Result<usize> { 170 unsafe { syscall0(SYS_GETEUID) } 171 } 172 173 /// Get the current group ID 174 pub fn getgid() -> Result<usize> { 175 unsafe { syscall0(SYS_GETGID) } 176 } 177 178 /// Get the current namespace 179 pub fn getns() -> Result<usize> { 180 unsafe { syscall0(SYS_GETNS) } 181 } 182 183 /// Get the current process ID 184 pub fn getpid() -> Result<usize> { 185 unsafe { syscall0(SYS_GETPID) } 186 } 187 188 /// Get the process group ID 189 pub fn getpgid(pid: usize) -> Result<usize> { 190 unsafe { syscall1(SYS_GETPGID, pid) } 191 } 192 193 /// Get the parent process ID 194 pub fn getppid() -> Result<usize> { 195 unsafe { syscall0(SYS_GETPPID) } 196 } 197 198 /// Get the current user ID 199 pub fn getuid() -> Result<usize> { 200 unsafe { syscall0(SYS_GETUID) } 201 } 202 203 /// Set the I/O privilege level 204 /// 205 /// # Errors 206 /// 207 /// * `EPERM` - `uid != 0` 208 /// * `EINVAL` - `level > 3` 209 pub unsafe fn iopl(level: usize) -> Result<usize> { 210 syscall1(SYS_IOPL, level) 211 } 212 213 /// Send a signal `sig` to the process identified by `pid` 214 pub fn kill(pid: usize, sig: usize) -> Result<usize> { 215 unsafe { syscall2(SYS_KILL, pid, sig) } 216 } 217 218 /// Create a link to a file 219 pub unsafe fn link(old: *const u8, new: *const u8) -> Result<usize> { 220 syscall2(SYS_LINK, old as usize, new as usize) 221 } 222 223 /// Seek to `offset` bytes in a file descriptor 224 pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result<usize> { 225 unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) } 226 } 227 228 /// Make a new scheme namespace 229 pub fn mkns(schemes: &[[usize; 2]]) -> Result<usize> { 230 unsafe { syscall2(SYS_MKNS, schemes.as_ptr() as usize, schemes.len()) } 231 } 232 233 /// Change mapping flags 234 pub unsafe fn mprotect(addr: usize, size: usize, flags: MapFlags) -> Result<usize> { 235 syscall3(SYS_MPROTECT, addr, size, flags.bits()) 236 } 237 238 /// Sleep for the time specified in `req` 239 pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result<usize> { 240 unsafe { syscall2(SYS_NANOSLEEP, req as *const TimeSpec as usize, 241 rem as *mut TimeSpec as usize) } 242 } 243 244 /// Open a file 245 pub fn open<T: AsRef<str>>(path: T, flags: usize) -> Result<usize> { 246 unsafe { syscall3(SYS_OPEN, path.as_ref().as_ptr() as usize, path.as_ref().len(), flags) } 247 } 248 249 /// Allocate frames, linearly in physical memory. 250 /// 251 /// # Errors 252 /// 253 /// * `EPERM` - `uid != 0` 254 /// * `ENOMEM` - the system has run out of available memory 255 pub unsafe fn physalloc(size: usize) -> Result<usize> { 256 syscall1(SYS_PHYSALLOC, size) 257 } 258 259 /// Allocate frames, linearly in physical memory, with an extra set of flags. If the flags contain 260 /// [`PARTIAL_ALLOC`], this will result in `physalloc3` with `min = 1`. 261 /// 262 /// Refer to the simpler [`physalloc`] and the more complex [`physalloc3`], that this convenience 263 /// function is based on. 264 /// 265 /// # Errors 266 /// 267 /// * `EPERM` - `uid != 0` 268 /// * `ENOMEM` - the system has run out of available memory 269 pub unsafe fn physalloc2(size: usize, flags: usize) -> Result<usize> { 270 let mut ret = 1usize; 271 physalloc3(size, flags, &mut ret) 272 } 273 274 /// Allocate frames, linearly in physical memory, with an extra set of flags. If the flags contain 275 /// [`PARTIAL_ALLOC`], the `min` parameter specifies the number of frames that have to be allocated 276 /// for this operation to succeed. The return value is the offset of the first frame, and `min` is 277 /// overwritten with the number of frames actually allocated. 278 /// 279 /// Refer to the simpler [`physalloc`] and the simpler library function [`physalloc2`]. 280 /// 281 /// # Errors 282 /// 283 /// * `EPERM` - `uid != 0` 284 /// * `ENOMEM` - the system has run out of available memory 285 /// * `EINVAL` - `min = 0` 286 pub unsafe fn physalloc3(size: usize, flags: usize, min: &mut usize) -> Result<usize> { 287 syscall3(SYS_PHYSALLOC3, size, flags, min as *mut usize as usize) 288 } 289 290 /// Free physically allocated pages 291 /// 292 /// # Errors 293 /// 294 /// * `EPERM` - `uid != 0` 295 pub unsafe fn physfree(physical_address: usize, size: usize) -> Result<usize> { 296 syscall2(SYS_PHYSFREE, physical_address, size) 297 } 298 299 /// Map physical memory to virtual memory 300 /// 301 /// # Errors 302 /// 303 /// * `EPERM` - `uid != 0` 304 pub unsafe fn physmap(physical_address: usize, size: usize, flags: PhysmapFlags) -> Result<usize> { 305 syscall3(SYS_PHYSMAP, physical_address, size, flags.bits()) 306 } 307 308 /// Unmap previously mapped physical memory 309 /// 310 /// # Errors 311 /// 312 /// * `EPERM` - `uid != 0` 313 /// * `EFAULT` - `virtual_address` has not been mapped 314 pub unsafe fn physunmap(virtual_address: usize) -> Result<usize> { 315 syscall1(SYS_PHYSUNMAP, virtual_address) 316 } 317 318 /// Create a pair of file descriptors referencing the read and write ends of a pipe 319 pub fn pipe2(fds: &mut [usize; 2], flags: usize) -> Result<usize> { 320 unsafe { syscall2(SYS_PIPE2, fds.as_ptr() as usize, flags) } 321 } 322 323 /// Read from a file descriptor into a buffer 324 pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> { 325 unsafe { syscall3(SYS_READ, fd, buf.as_mut_ptr() as usize, buf.len()) } 326 } 327 328 /// Remove a directory 329 pub fn rmdir<T: AsRef<str>>(path: T) -> Result<usize> { 330 unsafe { syscall2(SYS_RMDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) } 331 } 332 333 /// Set the process group ID 334 pub fn setpgid(pid: usize, pgid: usize) -> Result<usize> { 335 unsafe { syscall2(SYS_SETPGID, pid, pgid) } 336 } 337 338 /// Set the current process group IDs 339 pub fn setregid(rgid: usize, egid: usize) -> Result<usize> { 340 unsafe { syscall2(SYS_SETREGID, rgid, egid) } 341 } 342 343 /// Make a new scheme namespace 344 pub fn setrens(rns: usize, ens: usize) -> Result<usize> { 345 unsafe { syscall2(SYS_SETRENS, rns, ens) } 346 } 347 348 /// Set the current process user IDs 349 pub fn setreuid(ruid: usize, euid: usize) -> Result<usize> { 350 unsafe { syscall2(SYS_SETREUID, ruid, euid) } 351 } 352 353 /// Set up a signal handler 354 pub fn sigaction(sig: usize, act: Option<&SigAction>, oldact: Option<&mut SigAction>) -> Result<usize> { 355 unsafe { syscall4(SYS_SIGACTION, sig, 356 act.map(|x| x as *const _).unwrap_or_else(ptr::null) as usize, 357 oldact.map(|x| x as *mut _).unwrap_or_else(ptr::null_mut) as usize, 358 restorer as usize) } 359 } 360 361 /// Get and/or set signal masks 362 pub fn sigprocmask(how: usize, set: Option<&[u64; 2]>, oldset: Option<&mut [u64; 2]>) -> Result<usize> { 363 unsafe { syscall3(SYS_SIGPROCMASK, how, 364 set.map(|x| x as *const _).unwrap_or_else(ptr::null) as usize, 365 oldset.map(|x| x as *mut _).unwrap_or_else(ptr::null_mut) as usize) } 366 } 367 368 // Return from signal handler 369 pub fn sigreturn() -> Result<usize> { 370 unsafe { syscall0(SYS_SIGRETURN) } 371 } 372 373 /// Set the file mode creation mask 374 pub fn umask(mask: usize) -> Result<usize> { 375 unsafe { syscall1(SYS_UMASK, mask) } 376 } 377 378 /// Remove a file 379 pub fn unlink<T: AsRef<str>>(path: T) -> Result<usize> { 380 unsafe { syscall2(SYS_UNLINK, path.as_ref().as_ptr() as usize, path.as_ref().len()) } 381 } 382 383 /// Convert a virtual address to a physical one 384 /// 385 /// # Errors 386 /// 387 /// * `EPERM` - `uid != 0` 388 pub unsafe fn virttophys(virtual_address: usize) -> Result<usize> { 389 syscall1(SYS_VIRTTOPHYS, virtual_address) 390 } 391 392 /// Check if a child process has exited or received a signal 393 pub fn waitpid(pid: usize, status: &mut usize, options: WaitFlags) -> Result<usize> { 394 unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options.bits()) } 395 } 396 397 /// Write a buffer to a file descriptor 398 /// 399 /// The kernel will attempt to write the bytes in `buf` to the file descriptor `fd`, returning 400 /// either an `Err`, explained below, or `Ok(count)` where `count` is the number of bytes which 401 /// were written. 402 /// 403 /// # Errors 404 /// 405 /// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block 406 /// * `EBADF` - the file descriptor is not valid or is not open for writing 407 /// * `EFAULT` - `buf` does not point to the process's addressible memory 408 /// * `EIO` - an I/O error occurred 409 /// * `ENOSPC` - the device containing the file descriptor has no room for data 410 /// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed 411 pub fn write(fd: usize, buf: &[u8]) -> Result<usize> { 412 unsafe { syscall3(SYS_WRITE, fd, buf.as_ptr() as usize, buf.len()) } 413 } 414 415 /// Yield the process's time slice to the kernel 416 /// 417 /// This function will return Ok(0) on success 418 pub fn sched_yield() -> Result<usize> { 419 unsafe { syscall0(SYS_YIELD) } 420 } 421