diff --git a/.travis.yml b/.travis.yml index dae224e1a481144c90e8f81b63e116cdc60ece19..15083598be4e0726fba9aa4840687cef44533d82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ cache: cargo before_script: - rustup component add rustfmt-preview - rustup target add x86_64-unknown-redox + - rustup target add aarch64-unknown-linux-gnu script: - bash ./ci.sh notifications: diff --git a/Cargo.lock b/Cargo.lock index 06030c19ea05d5922a0af3a6571c44f193a17294..f2bdefd4a5261e3fd2c2c34996d0a79ddba7ed6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,6 +31,11 @@ dependencies = [ "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cc" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" version = "0.1.2" @@ -105,11 +110,6 @@ name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "gcc" -version = "0.3.54" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "grp" version = "0.1.0" @@ -258,6 +258,7 @@ dependencies = [ "mman 0.1.0", "platform 0.1.0", "semaphore 0.1.0", + "stat 0.1.0", "stdio 0.1.0", "stdlib 0.1.0", "string 0.1.0", @@ -440,6 +441,14 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "stat" +version = "0.1.0" +dependencies = [ + "cbindgen 0.5.0", + "platform 0.1.0", +] + [[package]] name = "stdio" version = "0.1.0" @@ -456,6 +465,7 @@ version = "0.1.0" dependencies = [ "cbindgen 0.5.0", "ctype 0.1.0", + "errno 0.1.0", "platform 0.1.0", "ralloc 1.0.0", ] @@ -576,7 +586,7 @@ dependencies = [ name = "va_list-helper" version = "0.0.2" dependencies = [ - "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -625,13 +635,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" "checksum atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" +"checksum cc 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9be26b24e988625409b19736d130f0c7d224f01d06454b5f81d8d23d6c1a618f" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum clap 2.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1c07b9257a00f3fc93b7f3c417fc15607ec7a56823bc2c37ec744e266387de5b" "checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins.git)" = "<none>" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum libc 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)" = "56aebce561378d99a0bb578f8cb15b6114d2a1814a6c7949bbe646d968bb4fa9" diff --git a/Cargo.toml b/Cargo.toml index 4bb5d97b8abd64fbed9189f57220bf525c32f17c..6d7103c8f7ae425671273f2a989ad4ed8dd5addb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ fcntl = { path = "src/fcntl" } grp = { path = "src/grp" } semaphore = { path = "src/semaphore" } mman = { path = "src/mman" } +stat = { path = "src/stat" } stdio = { path = "src/stdio" } stdlib = { path = "src/stdlib" } string = { path = "src/string" } diff --git a/README.md b/README.md index a48d27fe7a8ecc2202122374885f32294e49ed47..59d8525083085602fcd77d4118225f79b650d88d 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,13 @@ The motivation for this project is twofold: Reduce issues the redox crew was hav ## Contributing Just search for any invocation of the `unimplemented` macro, and hop in! The ci server checks builds for linux and redox, checks formatting (via rustfmt), and runs the test suite. Run `ci.sh` locally to check that your changes will pass travis. Use `fmt.sh` to format your code and `test.sh` to run the C test suite. + +## Supported OSes + + - RedoxOS + - Linux + +## Supported architectures + + - x86\_64 + - Aarch64 diff --git a/bindgen_transform.sh b/bindgen_transform.sh index a5ddde9fbbed90f12efac15637e8e7759725127b..b0f122edb8de0f2d59add943c96d3a895246e35f 100755 --- a/bindgen_transform.sh +++ b/bindgen_transform.sh @@ -1,4 +1,4 @@ -sed -i 's/::std::os::raw::/libc::/g' $1 +sed -i 's/::std::os::raw:://g' $1 perl -i -p0e 's/extern "C" \{\n pub fn/#[no_mangle]\npub extern "C" fn/g' $1 perl -i -p0e 's/;\n\}/ {\n unimplemented!();\n\}\n/g' $1 rustfmt $1 diff --git a/ci.sh b/ci.sh index 6fe90aaf9e6d9f94d658d9700b2e1588ed7c94c7..fd7dd91a480ac2b1f8ee9d3230b3210b3367440d 100755 --- a/ci.sh +++ b/ci.sh @@ -4,3 +4,9 @@ set -ex ./fmt.sh -- --write-mode=diff ./test.sh cargo build --target=x86_64-unknown-redox +if [ $(arch) == "x86_64" ] +then + cargo build --target=aarch64-unknown-linux-gnu +else + cargo build --target=x86_64-unknown-linux-gnu +fi diff --git a/include/sys/stat.h b/include/sys/stat.h new file mode 100644 index 0000000000000000000000000000000000000000..97836d36b0c98f591924a3791dd675753bc2ecb1 --- /dev/null +++ b/include/sys/stat.h @@ -0,0 +1,39 @@ +#ifndef _STAT_H +#define _STAT_H + +#include <sys/types.h> + +struct stat { + dev_t st_dev; + ino_t st_ino; + nlink_t st_nlink; + mode_t st_mode; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + blksize_t st_blksize; + time_t st_atim; + time_t st_mtim; + time_t st_ctim; +}; + +int chmod(const char *path, mode_t mode); + +int fchmod(int fildes, mode_t mode); + +int fstat(int fildes, struct stat *buf); + +int lstat(const char *path, struct stat *buf); + +int mkdir(const char *path, mode_t mode); + +int mkfifo(const char *path, mode_t mode); + +int mknod(const char *path, mode_t mode, dev_t dev); + +int stat(const char *file, struct stat *buf); + +mode_t umask(mode_t mask); + +#endif /* _STAT_H */ diff --git a/include/sys/types.h b/include/sys/types.h index 6f770aa64c19aa215a00a8c898ad6a1d66a68c45..0813cddfe4974a14426f1475a8693c66cb23498d 100644 --- a/include/sys/types.h +++ b/include/sys/types.h @@ -1,17 +1,27 @@ #ifndef _SYS_TYPES_H #define _SYS_TYPES_H +typedef long blksize_t; + +typedef long dev_t; + +typedef unsigned long ino_t; + typedef int gid_t; typedef int uid_t; typedef int mode_t; +typedef unsigned long nlink_t; + typedef long off_t; typedef int pid_t; typedef long ssize_t; +typedef long time_t; + typedef int useconds_t; #endif /* _SYS_TYPES_H */ diff --git a/src/lib.rs b/src/lib.rs index 52053e45801c335ca0518b57d5c4c0a1d6e3c7ce..cd56891d761912eec73aaab3d046adbcb96f9c1f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ extern crate fcntl; extern crate grp; extern crate mman; extern crate semaphore; +extern crate stat; extern crate stdio; extern crate stdlib; extern crate string; diff --git a/src/platform/src/linux/mod.rs b/src/platform/src/linux/mod.rs index 5f0066c2a4fc0df618407780d173978868092e57..daff60cb5760fde81bd0776f39f94af6f3fd73ea 100644 --- a/src/platform/src/linux/mod.rs +++ b/src/platform/src/linux/mod.rs @@ -4,6 +4,7 @@ use errno; use types::*; const AT_FDCWD: c_int = -100; +const AT_REMOVEDIR: c_int = 0x200; pub fn e(sys: usize) -> usize { if (sys as isize) < 0 && (sys as isize) >= -256 { @@ -67,7 +68,7 @@ pub fn fcntl(fildes: c_int, cmd: c_int, arg: c_int) -> c_int { } pub fn fork() -> pid_t { - e(unsafe { syscall!(FORK) }) as pid_t + e(unsafe { syscall!(CLONE, 17, 0) }) as pid_t } pub fn fsync(fildes: c_int) -> c_int { @@ -115,7 +116,11 @@ pub fn getuid() -> uid_t { } pub fn link(path1: *const c_char, path2: *const c_char) -> c_int { - e(unsafe { syscall!(LINKAT, AT_FDCWD, path1, path2) }) as c_int + e(unsafe { syscall!(LINKAT, AT_FDCWD, path1, AT_FDCWD, path2, 0) }) as c_int +} + +pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int { + e(unsafe { syscall!(MKDIRAT, AT_FDCWD, path, mode) }) as c_int } pub fn open(path: *const c_char, oflag: c_int, mode: mode_t) -> c_int { @@ -130,6 +135,26 @@ pub fn read(fildes: c_int, buf: &mut [u8]) -> ssize_t { e(unsafe { syscall!(READ, fildes, buf.as_mut_ptr(), buf.len()) }) as ssize_t } +pub fn rmdir(path: *const c_char) -> c_int { + e(unsafe { syscall!(UNLINKAT, AT_FDCWD, path, AT_REMOVEDIR) }) as c_int +} + +pub fn setpgid(pid: pid_t, pgid: pid_t) -> c_int { + e(unsafe { syscall!(SETPGID, pid, pgid) }) as c_int +} + +pub fn setregid(rgid: gid_t, egid: gid_t) -> c_int { + e(unsafe { syscall!(SETREGID, rgid, egid) }) as c_int +} + +pub fn setreuid(ruid: uid_t, euid: uid_t) -> c_int { + e(unsafe { syscall!(SETREUID, ruid, euid) }) as c_int +} + +pub fn unlink(path: *const c_char) -> c_int { + e(unsafe { syscall!(UNLINKAT, AT_FDCWD, path, 0) }) as c_int +} + pub fn write(fildes: c_int, buf: &[u8]) -> ssize_t { e(unsafe { syscall!(WRITE, fildes, buf.as_ptr(), buf.len()) }) as ssize_t } diff --git a/src/platform/src/redox/mod.rs b/src/platform/src/redox/mod.rs index edf9ad1724f70436954c433dda23a61acc96e18b..0ea4bda2073454a74f9968f0c351413b5471f741 100644 --- a/src/platform/src/redox/mod.rs +++ b/src/platform/src/redox/mod.rs @@ -1,6 +1,7 @@ use core::ptr; use core::slice; use syscall; +use syscall::flag::*; use c_str; use errno; @@ -122,6 +123,18 @@ pub fn link(path1: *const c_char, path2: *const c_char) -> c_int { e(unsafe { syscall::link(path1.as_ptr(), path2.as_ptr()) }) as c_int } +pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int { + let flags = O_CREAT | O_EXCL | O_CLOEXEC | O_DIRECTORY | mode as usize & 0o777; + let path = unsafe { c_str(path) }; + match syscall::open(path, flags) { + Ok(fd) => { + syscall::close(fd); + 0 + } + Err(err) => e(Err(err)) as c_int, + } +} + pub fn open(path: *const c_char, oflag: c_int, mode: mode_t) -> c_int { let path = unsafe { c_str(path) }; e(syscall::open(path, (oflag as usize) | (mode as usize))) as c_int @@ -139,6 +152,28 @@ pub fn read(fd: c_int, buf: &mut [u8]) -> ssize_t { e(syscall::read(fd as usize, buf)) as ssize_t } +pub fn rmdir(path: *const c_char) -> c_int { + let path = unsafe { c_str(path) }; + e(syscall::rmdir(path)) as c_int +} + +pub fn setpgid(pid: pid_t, pgid: pid_t) -> c_int { + e(syscall::setpgid(pid as usize, pgid as usize)) as c_int +} + +pub fn setregid(rgid: gid_t, egid: gid_t) -> c_int { + e(syscall::setregid(rgid as usize, egid as usize)) as c_int +} + +pub fn setreuid(ruid: uid_t, euid: uid_t) -> c_int { + e(syscall::setreuid(ruid as usize, euid as usize)) as c_int +} + +pub fn unlink(path: *const c_char) -> c_int { + let path = unsafe { c_str(path) }; + e(syscall::unlink(path)) as c_int +} + pub fn write(fd: c_int, buf: &[u8]) -> ssize_t { e(syscall::write(fd as usize, buf)) as ssize_t } diff --git a/src/platform/src/types.rs b/src/platform/src/types.rs index 0057825f297576d2cfc74c6d42f7683b22a64314..786af774d50c671dd6e66d39fed20e7c35181512 100644 --- a/src/platform/src/types.rs +++ b/src/platform/src/types.rs @@ -52,6 +52,10 @@ pub type time_t = i64; pub type pid_t = usize; pub type gid_t = usize; pub type uid_t = usize; +pub type dev_t = usize; +pub type ino_t = usize; +pub type nlink_t = usize; +pub type blksize_t = isize; pub type useconds_t = i32; pub type suseconds_t = i64; diff --git a/src/stat/Cargo.toml b/src/stat/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..7b779a2cf59d360792e692074bfa66fd4925f1d7 --- /dev/null +++ b/src/stat/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "stat" +version = "0.1.0" +authors = ["Jeremy Soller <jackpot51@gmail.com>"] +build = "build.rs" + +[build-dependencies] +cbindgen = { path = "../../cbindgen" } + +[dependencies] +platform = { path = "../platform" } diff --git a/src/stat/build.rs b/src/stat/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..74a9a42fe9884469a1fe3e598c65b4179da6b0f6 --- /dev/null +++ b/src/stat/build.rs @@ -0,0 +1,13 @@ +extern crate cbindgen; + +use std::{env, fs}; + +fn main() { + /* + *let crate_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"); + *fs::create_dir_all("../../target/include").expect("failed to create include directory"); + *cbindgen::generate(crate_dir) + * .expect("failed to generate bindings") + * .write_to_file("../../target/include/sys/stat.h"); + */ +} diff --git a/src/stat/cbindgen.toml b/src/stat/cbindgen.toml new file mode 100644 index 0000000000000000000000000000000000000000..d4f38953dbe8afa0f97c39791403b2ac7df5ae95 --- /dev/null +++ b/src/stat/cbindgen.toml @@ -0,0 +1,6 @@ +sys_includes = ["sys/types.h"] +include_guard = "_SYS_STAT_H" +language = "C" + +[enum] +prefix_with_name = true diff --git a/src/stat/src/lib.rs b/src/stat/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..b8e2db57439020188be9511bc3c62235eee8e940 --- /dev/null +++ b/src/stat/src/lib.rs @@ -0,0 +1,75 @@ +//! stat implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysstat.h.html + +#![no_std] + +extern crate platform; + +use platform::types::*; + +#[repr(C)] +pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_nlink: nlink_t, + pub st_mode: mode_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub st_size: off_t, + pub st_blksize: blksize_t, + pub st_atim: time_t, + pub st_mtim: time_t, + pub st_ctim: time_t, +} + +#[no_mangle] +pub extern "C" fn chmod(path: *const c_char, mode: mode_t) -> c_int { + unimplemented!(); +} + +#[no_mangle] +pub extern "C" fn fchmod(fildes: c_int, mode: mode_t) -> c_int { + unimplemented!(); +} + +#[no_mangle] +pub extern "C" fn fstat(fildes: c_int, buf: *mut stat) -> c_int { + unimplemented!(); +} + +#[no_mangle] +pub extern "C" fn lstat(path: *const c_char, buf: *mut stat) -> c_int { + unimplemented!(); +} + +#[no_mangle] +pub extern "C" fn mkdir(path: *const c_char, mode: mode_t) -> c_int { + platform::mkdir(path, mode) +} + +#[no_mangle] +pub extern "C" fn mkfifo(path: *const c_char, mode: mode_t) -> c_int { + unimplemented!(); +} + +#[no_mangle] +pub extern "C" fn mknod(path: *const c_char, mode: mode_t, dev: dev_t) -> c_int { + unimplemented!(); +} + +#[no_mangle] +pub extern "C" fn stat(file: *const c_char, buf: *mut stat) -> c_int { + unimplemented!(); +} + +#[no_mangle] +pub extern "C" fn umask(mask: mode_t) -> mode_t { + unimplemented!(); +} + +/* +#[no_mangle] +pub extern "C" fn func(args) -> c_int { + unimplemented!(); +} +*/ diff --git a/src/stdio/src/printf.rs b/src/stdio/src/printf.rs index d1ce976cbd28a8da41c9c77ded26de8a6911a4e3..093ee82c122d6f902e00d8f9c05f2653dcdbc432 100644 --- a/src/stdio/src/printf.rs +++ b/src/stdio/src/printf.rs @@ -1,13 +1,9 @@ -use core::fmt; +use core::{fmt, mem, slice, str}; use platform::types::*; use vl::VaList; pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaList) -> c_int { - use core::fmt::Write; - use core::slice; - use core::str; - extern "C" { fn strlen(s: *const c_char) -> size_t; } @@ -39,6 +35,13 @@ pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaL found_percent = false; } + 'f' | 'F' => { + let a = ap.get::<f64>(); + + w.write_fmt(format_args!("{}", a)); + + found_percent = false; + } 'n' => { let _a = ap.get::<c_int>(); @@ -82,6 +85,13 @@ pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaL found_percent = false; } + 'o' => { + let a = ap.get::<c_uint>(); + + w.write_fmt(format_args!("{:o}", a)); + + found_percent = false; + } '-' => {} '+' => {} ' ' => {} diff --git a/src/stdlib/Cargo.toml b/src/stdlib/Cargo.toml index 4a2fb9f88ef60db4aa7c58e6dfebd7b123631a47..97f5d44187b6fc477f3bb8ece793d9fd6d56fddd 100644 --- a/src/stdlib/Cargo.toml +++ b/src/stdlib/Cargo.toml @@ -11,3 +11,4 @@ cbindgen = { path = "../../cbindgen" } platform = { path = "../platform" } ralloc = { path = "../../ralloc", default-features = false } ctype = { path = "../ctype" } +errno = { path = "../errno" } diff --git a/src/stdlib/src/lib.rs b/src/stdlib/src/lib.rs index fd25f5b731be06d721a4e98f50f34b5ca11983a7..dea8dbd13a4b17def216925f39324048faca1c66 100644 --- a/src/stdlib/src/lib.rs +++ b/src/stdlib/src/lib.rs @@ -5,9 +5,13 @@ #![feature(global_allocator)] extern crate ctype; +extern crate errno; extern crate platform; extern crate ralloc; +use core::{ptr, str}; + +use errno::*; use platform::types::*; #[global_allocator] @@ -52,8 +56,8 @@ pub unsafe extern "C" fn atexit(func: Option<extern "C" fn()>) -> c_int { } #[no_mangle] -pub extern "C" fn atof(s: *const c_char) -> c_double { - unimplemented!(); +pub unsafe extern "C" fn atof(s: *const c_char) -> c_double { + strtod(s, ptr::null_mut()) } macro_rules! dec_num_from_ascii { @@ -396,13 +400,208 @@ pub extern "C" fn srandom(seed: c_uint) { } #[no_mangle] -pub extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double { - unimplemented!(); +pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double { + //TODO: endptr + + use core::str::FromStr; + + let s_str = str::from_utf8_unchecked(platform::c_str(s)); + match f64::from_str(s_str) { + Ok(ok) => ok as c_double, + Err(_err) => { + platform::errno = EINVAL; + 0.0 + } + } } #[no_mangle] -pub extern "C" fn strtol(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_long { - unimplemented!(); +pub unsafe extern "C" fn strtol( + s: *const c_char, + endptr: *mut *const c_char, + base: c_int, +) -> c_long { + let set_endptr = |idx: isize| { + if !endptr.is_null() { + *endptr = s.offset(idx); + } + }; + + let invalid_input = || { + platform::errno = EINVAL; + set_endptr(0); + }; + + // only valid bases are 2 through 36 + if base != 0 && (base < 2 || base > 36) { + invalid_input(); + return 0; + } + + let mut idx = 0; + + // skip any whitespace at the beginning of the string + while ctype::isspace(*s.offset(idx) as c_int) != 0 { + idx += 1; + } + + // check for +/- + let positive = match is_positive(*s.offset(idx)) { + Some((pos, i)) => { + idx += i; + pos + } + None => { + invalid_input(); + return 0; + } + }; + + // convert the string to a number + let num_str = s.offset(idx); + let res = match base { + 0 => detect_base(num_str).and_then(|(base, i)| convert_integer(num_str.offset(i), base)), + 8 => convert_octal(num_str), + 16 => convert_hex(num_str), + _ => convert_integer(num_str, base), + }; + + // check for error parsing octal/hex prefix + // also check to ensure a number was indeed parsed + let (num, i, _) = match res { + Some(res) => res, + None => { + invalid_input(); + return 0; + } + }; + idx += i; + + // account for the sign + let mut num = num as c_long; + num = if num.is_negative() { + platform::errno = ERANGE; + if positive { + c_long::max_value() + } else { + c_long::min_value() + } + } else { + if positive { + num + } else { + -num + } + }; + + set_endptr(idx); + + num +} + +fn is_positive(ch: c_char) -> Option<(bool, isize)> { + match ch { + 0 => None, + ch if ch == b'+' as c_char => Some((true, 1)), + ch if ch == b'-' as c_char => Some((false, 1)), + _ => Some((true, 0)), + } +} + +fn detect_base(s: *const c_char) -> Option<(c_int, isize)> { + let first = unsafe { *s } as u8; + match first { + 0 => None, + b'0' => { + let second = unsafe { *s.offset(1) } as u8; + if second == b'X' || second == b'x' { + Some((16, 2)) + } else if second >= b'0' && second <= b'7' { + Some((8, 1)) + } else { + // in this case, the prefix (0) is going to be the number + Some((8, 0)) + } + } + _ => Some((10, 0)), + } +} + +unsafe fn convert_octal(s: *const c_char) -> Option<(c_ulong, isize, bool)> { + if *s != 0 && *s == b'0' as c_char { + if let Some((val, idx, overflow)) = convert_integer(s.offset(1), 8) { + Some((val, idx + 1, overflow)) + } else { + // in case the prefix is not actually a prefix + Some((0, 1, false)) + } + } else { + None + } +} + +unsafe fn convert_hex(s: *const c_char) -> Option<(c_ulong, isize, bool)> { + if (*s != 0 && *s == b'0' as c_char) + && (*s.offset(1) != 0 && (*s.offset(1) == b'x' as c_char || *s.offset(1) == b'X' as c_char)) + { + convert_integer(s.offset(2), 16).map(|(val, idx, overflow)| (val, idx + 2, overflow)) + } else { + None + } +} + +fn convert_integer(s: *const c_char, base: c_int) -> Option<(c_ulong, isize, bool)> { + // -1 means the character is invalid + #[cfg_attr(rustfmt, rustfmt_skip)] + const LOOKUP_TABLE: [c_long; 256] = [ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + ]; + + let mut num: c_ulong = 0; + let mut idx = 0; + let mut overflowed = false; + + loop { + let val = unsafe { LOOKUP_TABLE[*s.offset(idx) as usize] }; + if val == -1 || val as c_int >= base { + break; + } else { + if let Some(res) = num.checked_mul(base as c_ulong) + .and_then(|num| num.checked_add(val as c_ulong)) + { + num = res; + } else { + unsafe { + platform::errno = ERANGE; + } + num = c_ulong::max_value(); + overflowed = true; + } + + idx += 1; + } + } + + if idx > 0 { + Some((num, idx, overflowed)) + } else { + None + } } #[no_mangle] diff --git a/src/unistd/src/lib.rs b/src/unistd/src/lib.rs index ea4609ba50405de7305fd72437092fa666a23e92..8a1d149f887b8aad5ab05f60d54d8c3607a60f31 100644 --- a/src/unistd/src/lib.rs +++ b/src/unistd/src/lib.rs @@ -225,7 +225,7 @@ pub extern "C" fn getpgid(pid: pid_t) -> pid_t { #[no_mangle] pub extern "C" fn getpgrp() -> pid_t { - unimplemented!(); + platform::getpgid(platform::getpid()) } #[no_mangle] @@ -336,7 +336,7 @@ pub extern "C" fn readlink(path: *const c_char, buf: *mut c_char, bufsize: size_ #[no_mangle] pub extern "C" fn rmdir(path: *const c_char) -> c_int { - unimplemented!(); + platform::rmdir(path) } #[no_mangle] @@ -351,7 +351,7 @@ pub extern "C" fn setgid(gid: gid_t) -> c_int { #[no_mangle] pub extern "C" fn setpgid(pid: pid_t, pgid: pid_t) -> c_int { - unimplemented!(); + platform::setpgid(pid, pgid) } #[no_mangle] @@ -361,12 +361,12 @@ pub extern "C" fn setpgrp() -> pid_t { #[no_mangle] pub extern "C" fn setregid(rgid: gid_t, egid: gid_t) -> c_int { - unimplemented!(); + platform::setregid(rgid, egid) } #[no_mangle] pub extern "C" fn setreuid(ruid: uid_t, euid: uid_t) -> c_int { - unimplemented!(); + platform::setreuid(ruid, euid) } #[no_mangle] @@ -436,7 +436,7 @@ pub extern "C" fn ualarm(useconds: useconds_t, interval: useconds_t) -> useconds #[no_mangle] pub extern "C" fn unlink(path: *const c_char) -> c_int { - unimplemented!(); + platform::unlink(path) } #[no_mangle] diff --git a/tests/.gitignore b/tests/.gitignore index e5819ec54577f63583b4398ca86d61af361a7ef1..42fe4750c666a6810fd66def2384df6045e3cc7c 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,5 +1,7 @@ +/gen/ /alloc /args +/atof /atoi /brk /chdir @@ -10,6 +12,7 @@ /dup.out /error /fchdir +/fcntl /fsync /ftruncate /ftruncate.out @@ -19,4 +22,8 @@ /math /pipe /printf +/rmdir +/setid +/unlink +/stdlib/strtol /write diff --git a/tests/Makefile b/tests/Makefile index d7fafcdb2eb5b54690b6b79f32b755644c04a106..24f1ba3a0443600b3e3d3433ca2f644ca1e9e223 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,5 +1,6 @@ BINS=\ alloc \ + atof \ atoi \ brk \ args \ @@ -17,6 +18,10 @@ BINS=\ math \ pipe \ printf \ + rmdir \ + setid \ + unlink \ + stdlib/strtol \ write all: $(BINS) @@ -25,7 +30,33 @@ clean: rm -f $(BINS) *.out run: $(BINS) - for bin in $(BINS); do echo "# $${bin} #"; "./$${bin}" test args; done + for bin in $(BINS); \ + do \ + echo "# $${bin} #"; \ + "./$${bin}" test args; \ + done + +expected: $(BINS) + rm -rf expected + mkdir -p expected + for bin in $(BINS); \ + do \ + echo "# $${bin} #"; \ + mkdir -p expected/`dirname $${bin}`; \ + "./$${bin}" test args > "expected/$${bin}.stdout" 2> "expected/$${bin}.stderr"; \ + done + +verify: $(BINS) + rm -rf gen + mkdir -p gen + for bin in $(BINS); \ + do \ + echo "# $${bin} #"; \ + mkdir -p gen/`dirname $${bin}`; \ + "./$${bin}" test args > "gen/$${bin}.stdout" 2> "gen/$${bin}.stderr"; \ + diff -u "gen/$${bin}.stdout" "expected/$${bin}.stdout"; \ + diff -u "gen/$${bin}.stderr" "expected/$${bin}.stderr"; \ + done GCCHEAD=\ -nostdinc \ diff --git a/tests/atof.c b/tests/atof.c new file mode 100644 index 0000000000000000000000000000000000000000..1bfb9d0e220d4029fadb86716017705061958146 --- /dev/null +++ b/tests/atof.c @@ -0,0 +1,8 @@ +#include <stdlib.h> +#include <stdio.h> + +int main(int argc, char* argv[]) { + double d = atof("-3.14"); + printf("%f\n", d); + return 0; +} diff --git a/tests/expected/alloc.stderr b/tests/expected/alloc.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/alloc.stdout b/tests/expected/alloc.stdout new file mode 100644 index 0000000000000000000000000000000000000000..74753f94e3cfa3f1e9b0374f2f82e4dff032316f --- /dev/null +++ b/tests/expected/alloc.stdout @@ -0,0 +1,2 @@ +malloc 0x55ac6c472618 +calloc 0x55ac6c472618 diff --git a/tests/expected/args.stderr b/tests/expected/args.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/args.stdout b/tests/expected/args.stdout new file mode 100644 index 0000000000000000000000000000000000000000..3b9ef538c3b9a209e24658fe4ef796b8983cc835 --- /dev/null +++ b/tests/expected/args.stdout @@ -0,0 +1 @@ +./args test args diff --git a/tests/expected/atof.stderr b/tests/expected/atof.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/atof.stdout b/tests/expected/atof.stdout new file mode 100644 index 0000000000000000000000000000000000000000..01e913dbfe725d2fdb0b96b99af47aed063f1792 --- /dev/null +++ b/tests/expected/atof.stdout @@ -0,0 +1 @@ +-3.14 diff --git a/tests/expected/atoi.stderr b/tests/expected/atoi.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/atoi.stdout b/tests/expected/atoi.stdout new file mode 100644 index 0000000000000000000000000000000000000000..d90e37cceac826425a16f83375fa2271261c4541 --- /dev/null +++ b/tests/expected/atoi.stdout @@ -0,0 +1,6 @@ +-42 +555 +1234567890 +-42 +555 +1234567890 diff --git a/tests/expected/brk.stderr b/tests/expected/brk.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/brk.stdout b/tests/expected/brk.stdout new file mode 100644 index 0000000000000000000000000000000000000000..c7e87198e01823db56563f4fe0fefe5b192dfb30 --- /dev/null +++ b/tests/expected/brk.stdout @@ -0,0 +1 @@ +brk exited with status code 0 diff --git a/tests/expected/chdir.stderr b/tests/expected/chdir.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/chdir.stdout b/tests/expected/chdir.stdout new file mode 100644 index 0000000000000000000000000000000000000000..6d79e11be0b87900d32ef232c49b0b99fc526f48 --- /dev/null +++ b/tests/expected/chdir.stdout @@ -0,0 +1,2 @@ +initial cwd: /home/jeremy/Projects/relibc/tests +final cwd: /home/jeremy/Projects/relibc diff --git a/tests/expected/create.stderr b/tests/expected/create.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/create.stdout b/tests/expected/create.stdout new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/ctype.stderr b/tests/expected/ctype.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/ctype.stdout b/tests/expected/ctype.stdout new file mode 100644 index 0000000000000000000000000000000000000000..e83b1e5f11ff31bed1bbfd1ab18e5f793a440275 --- /dev/null +++ b/tests/expected/ctype.stdout @@ -0,0 +1 @@ +Success: 0 diff --git a/tests/expected/dup.stderr b/tests/expected/dup.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/dup.stdout b/tests/expected/dup.stdout new file mode 100644 index 0000000000000000000000000000000000000000..20ec3fc2838660ac3a4dcb4428bd025b248e4fc5 --- /dev/null +++ b/tests/expected/dup.stdout @@ -0,0 +1 @@ +fd 4 duped into fd 5 diff --git a/tests/expected/error.stderr b/tests/expected/error.stderr new file mode 100644 index 0000000000000000000000000000000000000000..4eb19d82f37676f845b7b3a59a4991ce5a22996a --- /dev/null +++ b/tests/expected/error.stderr @@ -0,0 +1 @@ +perror: No such file or directory diff --git a/tests/expected/error.stdout b/tests/expected/error.stdout new file mode 100644 index 0000000000000000000000000000000000000000..f4ea5c920d19509171eff96610dc67881b4d6e04 --- /dev/null +++ b/tests/expected/error.stdout @@ -0,0 +1 @@ +errno: 2 = No such file or directory diff --git a/tests/expected/fchdir.stderr b/tests/expected/fchdir.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/fchdir.stdout b/tests/expected/fchdir.stdout new file mode 100644 index 0000000000000000000000000000000000000000..4c110c289b34afe90d556803fc35c38e5967d250 --- /dev/null +++ b/tests/expected/fchdir.stdout @@ -0,0 +1 @@ +fchdir exited with status code 0 diff --git a/tests/expected/fcntl.stderr b/tests/expected/fcntl.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/fcntl.stdout b/tests/expected/fcntl.stdout new file mode 100644 index 0000000000000000000000000000000000000000..20ec3fc2838660ac3a4dcb4428bd025b248e4fc5 --- /dev/null +++ b/tests/expected/fcntl.stdout @@ -0,0 +1 @@ +fd 4 duped into fd 5 diff --git a/tests/expected/fsync.stderr b/tests/expected/fsync.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/fsync.stdout b/tests/expected/fsync.stdout new file mode 100644 index 0000000000000000000000000000000000000000..0b3deee6ecb6b6d14b65744dafc7e1fe7e4e7312 --- /dev/null +++ b/tests/expected/fsync.stdout @@ -0,0 +1 @@ +fsync exited with status code 0 diff --git a/tests/expected/ftruncate.stderr b/tests/expected/ftruncate.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/ftruncate.stdout b/tests/expected/ftruncate.stdout new file mode 100644 index 0000000000000000000000000000000000000000..5f0c8d705411b4e130d4da724c02e521b8f75927 --- /dev/null +++ b/tests/expected/ftruncate.stdout @@ -0,0 +1 @@ +ftruncate exited with status code 0 diff --git a/tests/expected/getid.stderr b/tests/expected/getid.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/getid.stdout b/tests/expected/getid.stdout new file mode 100644 index 0000000000000000000000000000000000000000..a51fd84a302264be258b90f328bf59ade1eacb18 --- /dev/null +++ b/tests/expected/getid.stdout @@ -0,0 +1 @@ +egid: 1000, euid: 1000, gid: 1000, pgid: 23916, pid: 23933, ppid 23918, uid 1000 diff --git a/tests/expected/link.stderr b/tests/expected/link.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/link.stdout b/tests/expected/link.stdout new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/math.stderr b/tests/expected/math.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/math.stdout b/tests/expected/math.stdout new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/pipe.stderr b/tests/expected/pipe.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/pipe.stdout b/tests/expected/pipe.stdout new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/printf.stderr b/tests/expected/printf.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/printf.stdout b/tests/expected/printf.stdout new file mode 100644 index 0000000000000000000000000000000000000000..ad30d8fbca48dc82518f2786cbb220d29dd075d3 --- /dev/null +++ b/tests/expected/printf.stdout @@ -0,0 +1,8 @@ +percent: % +string: String +char: c +int: -16 +uint: 32 +hex: beef +HEX: C0FFEE +string: end diff --git a/tests/expected/rmdir.stderr b/tests/expected/rmdir.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/rmdir.stdout b/tests/expected/rmdir.stdout new file mode 100644 index 0000000000000000000000000000000000000000..be0153a5a554b913c6bc7a1309b0d6eeed423649 --- /dev/null +++ b/tests/expected/rmdir.stdout @@ -0,0 +1 @@ +rmdir exited with status code 0 diff --git a/tests/expected/write.stderr b/tests/expected/write.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/write.stdout b/tests/expected/write.stdout new file mode 100644 index 0000000000000000000000000000000000000000..980a0d5f19a64b4b30a87d4206aade58726b60e3 --- /dev/null +++ b/tests/expected/write.stdout @@ -0,0 +1 @@ +Hello World! diff --git a/tests/fcntl b/tests/fcntl deleted file mode 100755 index 4499cb1482f3157fa2e77cac3c4a42fcd72fedf3..0000000000000000000000000000000000000000 Binary files a/tests/fcntl and /dev/null differ diff --git a/tests/link.c b/tests/link.c index 3e36df81fbfd72fb472c5245aad3db84c05c5c6d..383575e8ce60e3a7d7fd57b71e2cb9b7d41f7c8e 100644 --- a/tests/link.c +++ b/tests/link.c @@ -1,5 +1,6 @@ #include <unistd.h> int main(int argc, char** argv) { - int status = link("link.c", "link.out"); + link("./link.c", "./link.out"); + perror("link"); } diff --git a/tests/rmdir.c b/tests/rmdir.c new file mode 100644 index 0000000000000000000000000000000000000000..cd9889380b802e770b11e462029d33b6cb20aeb7 --- /dev/null +++ b/tests/rmdir.c @@ -0,0 +1,9 @@ +#include <unistd.h> +#include <sys/stat.h> +#include <stdio.h> + +int main(int argc, char** argv) { + mkdir("foo", 0); + int status = rmdir("foo"); + printf("rmdir exited with status code %d\n", status); +} diff --git a/tests/setid.c b/tests/setid.c new file mode 100644 index 0000000000000000000000000000000000000000..ce2b42ea93e4ba464faaf9341ea38fd2da171f11 --- /dev/null +++ b/tests/setid.c @@ -0,0 +1,26 @@ +/* + * The process joins process group 0. + */ +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> + +int main( void ) + { + if( setpgid( getpid(), 0 ) == -1 ) { + perror( "setpgid" ); + } + printf( "%d belongs to process group %d\n", + getpid(), getpgrp() ); + + if( setregid(-1, -1) == -1 ) { + perror( "setregid" ); + } + printf("%d has egid %d and gid %d\n", getpid(), getegid(), getgid()); + + if( setreuid(-1, -1) == -1 ) { + perror( "setreuid" ); + } + printf("%d has euid %d and uid %d\n", getpid(), geteuid(), getuid()); + } diff --git a/tests/stdlib/strtol.c b/tests/stdlib/strtol.c new file mode 100644 index 0000000000000000000000000000000000000000..7d09883c64bb0daaa992ccbb3a7bab5eaec7e13b --- /dev/null +++ b/tests/stdlib/strtol.c @@ -0,0 +1,30 @@ +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> + +int main(int argc, char* argv[]) { + printf("%ld\n", strtol(" -42", NULL, 0)); + printf("%ld\n", strtol(" +555", NULL, 0)); + printf("%ld\n", strtol(" 1234567890 ", NULL, 0)); + + printf("%ld\n", strtol(" -42", NULL, 10)); + printf("%ld\n", strtol(" +555", NULL, 10)); + printf("%ld\n", strtol(" 1234567890 ", NULL, 10)); + + printf("%lx\n", strtol(" 0x38Acfg", NULL, 0)); + printf("%lx\n", strtol("0Xabcdef12", NULL, 16)); + + printf("%lo\n", strtol(" 073189", NULL, 0)); + printf("%lo\n", strtol(" 073189", NULL, 8)); + + printf("%lo\n", strtol(" 0b", NULL, 8)); + if(errno != 0) { + printf("errno is not 0 (%d), something went wrong\n", errno); + } + printf("%lo\n", strtol(" 0b", NULL, 0)); + if(errno != 0) { + printf("errno is not 0 (%d), something went wrong\n", errno); + } + + return 0; +} diff --git a/tests/unlink.c b/tests/unlink.c new file mode 100644 index 0000000000000000000000000000000000000000..0eceae0ac2891215ab2f531157476b6188952444 --- /dev/null +++ b/tests/unlink.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include <stdio.h> + +int main(int argc, char** argv) { + link("./unlink.c", "./unlink.out"); + perror("unlink"); +} diff --git a/va_list b/va_list index 4762a184501beedbb58ea218f0c84fea85685c35..ba5a07a744915b501acadb17e05db0f5d6552f72 160000 --- a/va_list +++ b/va_list @@ -1 +1 @@ -Subproject commit 4762a184501beedbb58ea218f0c84fea85685c35 +Subproject commit ba5a07a744915b501acadb17e05db0f5d6552f72