diff --git a/Makefile b/Makefile index 750bfbc5e..7a3822151 100644 --- a/Makefile +++ b/Makefile @@ -183,7 +183,13 @@ endef DEPLIBS := libc DEPPLUGS := # now, add in deps in src/utilname/deps.mk -$(foreach build,$(sort $(EXES) $(TESTS)),$(eval $(call DEP_INCLUDE,$(build)))) +# if we're testing, only consider the TESTS variable, +# otherwise consider the EXES variable +ifeq ($(MAKECMDGOALS),test) +$(foreach build,$(TESTS),$(eval $(call DEP_INCLUDE,$(build)))) +else +$(foreach build,$(sort $(TESTS) $(EXES)),$(eval $(call DEP_INCLUDE,$(build)))) +endif # uniqify deps DEPLIBS := $(sort $(DEPLIBS)) DEPPLUGS := $(sort $(DEPPLUGS)) @@ -248,8 +254,8 @@ endef # Test exe built rules define TEST_BUILD -test_$(1): $(TEMPDIR)/$(1)/$(1)_test $(BUILDDIR)/$(1) - $(call command,cp $(BUILDDIR)/$(1) $(TEMPDIR)/$(1) && cd $(TEMPDIR)/$(1) && $$<) +test_$(1): $(BUILDDIR)/$(1) $(TEMPDIR)/$(1)/$(1)_test + $(call command,cp $(BUILDDIR)/$(1) $(TEMPDIR)/$(1) && cd $(TEMPDIR)/$(1) && $(TEMPDIR)/$(1)/$(1)_test) $(TEMPDIR)/$(1)/$(1)_test: $(TESTDIR)/$(1).rs | $(TEMPDIR)/$(1) $(call command,$(RUSTC) $(RUSTCTESTFLAGS) $(DEP_EXTERN) --test -o $$@ $$<) diff --git a/src/chmod/chmod.rs b/src/chmod/chmod.rs index 828a89960..64015cf13 100644 --- a/src/chmod/chmod.rs +++ b/src/chmod/chmod.rs @@ -1,5 +1,5 @@ #![crate_name = "chmod"] -#![feature(collections, path_ext, fs_walk, rustc_private)] +#![feature(fs_walk, path_ext, rustc_private)] /* * This file is part of the uutils coreutils package. @@ -19,15 +19,11 @@ extern crate libc; extern crate regex; use std::ffi::CString; -use std::fs; -use std::io; -use std::io::Write; -use std::mem; -use std::u32; +use std::fs::{self, PathExt}; use std::path::Path; -use std::fs::PathExt; +use std::io::{Error, Write}; +use std::mem; use regex::Regex; -use libc::types::os::arch::posix01; #[path = "../common/util.rs"] #[macro_use] @@ -51,7 +47,7 @@ pub fn uumain(args: Vec) -> i32 { getopts::optflag("V", "version", "output version information and exit") ]; // TODO: sanitize input for - at beginning (e.g. chmod -x testfile). Solution is to add a to -x, making a-x - let mut matches = match getopts::getopts(args.tail(), &opts) { + let mut matches = match getopts::getopts(&args[1..], &opts) { Ok(m) => m, Err(f) => { crash!(1, "{}", f) @@ -69,7 +65,7 @@ Usage: Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.", name = NAME, version = VERSION, program = program, usage = getopts::usage("Change the mode of each FILE to MODE. \ - With --reference, change the mode of \ + \nWith --reference, change the mode of \ each FILE to that of RFILE.", &opts)); } else if matches.opt_present("version") { println!("{} v{}", NAME, VERSION); @@ -84,18 +80,18 @@ Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.", let preserve_root = matches.opt_present("preserve-root"); let recursive = matches.opt_present("recursive"); let fmode = matches.opt_str("reference").and_then(|fref| { - let mut stat : posix01::stat = unsafe { mem::uninitialized() }; + let mut stat : libc::stat = unsafe { mem::uninitialized() }; let statres = unsafe { libc::stat(fref.as_ptr() as *const i8, &mut stat as *mut libc::stat) }; if statres == 0 { Some(stat.st_mode) } else { - crash!(1, "{}", io::Error::last_os_error()) + crash!(1, "{}", Error::last_os_error()) } }); let cmode = if fmode.is_none() { let mode = matches.free.remove(0); - match verify_mode(mode.as_ref()) { + match verify_mode(&mode[..]) { Ok(_) => Some(mode), Err(f) => { show_error!("{}", f); @@ -153,7 +149,7 @@ fn chmod(files: Vec, changes: bool, quiet: bool, verbose: bool, preserve let mut r = Ok(()); for filename in files.iter() { - let filename = filename.as_ref(); + let filename = &filename[..]; let file = Path::new(filename); if file.exists() { if file.is_dir() { @@ -165,7 +161,19 @@ fn chmod(files: Vec, changes: bool, quiet: bool, verbose: bool, preserve crash!(1, "{}", f.to_string()); } }; - r = chmod(walk_dir.map(|x| x.ok().unwrap().path().to_str().unwrap().to_string()).collect(), changes, quiet, verbose, preserve_root, recursive, fmode, cmode).and(r); + // XXX: here (and elsewhere) we see that this impl will have issues + // with non-UTF-8 filenames. Using OsString won't fix this because + // on Windows OsStrings cannot be built out of non-UTF-8 chars. One + // possible fix is to use CStrings rather than Strings in the args + // to chmod() and chmod_file(). + r = chmod(walk_dir.filter_map(|x| match x { + Ok(o) => match o.path().into_os_string().to_str() { + Some(s) => Some(s.to_string()), + None => None, + }, + Err(e) => None, + }).collect(), + changes, quiet, verbose, preserve_root, recursive, fmode, cmode).and(r); r = chmod_file(&file, filename, changes, quiet, verbose, fmode, cmode).and(r); } } else { @@ -186,31 +194,34 @@ fn chmod(files: Vec, changes: bool, quiet: bool, verbose: bool, preserve } fn chmod_file(file: &Path, name: &str, changes: bool, quiet: bool, verbose: bool, fmode: Option, cmode: Option<&String>) -> Result<(), i32> { - let path = CString::new(name).unwrap(); + let path = CString::new(name).unwrap_or_else(|e| panic!("{}", e)); match fmode { Some(mode) => { if unsafe { libc::chmod(path.as_ptr(), mode) } == 0 { // TODO: handle changes, quiet, and verbose } else { - show_error!("{}", io::Error::last_os_error()); + show_error!("{}", Error::last_os_error()); return Err(1); } } None => { // TODO: make the regex processing occur earlier (i.e. once in the main function) static REGEXP: regex::Regex = regex!(r"^(([ugoa]*)((?:[-+=](?:[rwxXst]*|[ugo]))+))|([-+=]?[0-7]+)$"); - let mut stat : posix01::stat = unsafe { mem::uninitialized() }; + let mut stat : libc::stat = unsafe { mem::uninitialized() }; let statres = unsafe { libc::stat(path.as_ptr(), &mut stat as *mut libc::stat) }; let mut fperm = if statres == 0 { stat.st_mode } else { - show_error!("{}", io::Error::last_os_error()); + show_error!("{}", Error::last_os_error()); return Err(1); }; for mode in cmode.unwrap().split(',') { // cmode is guaranteed to be Some in this case let cap = REGEXP.captures(mode).unwrap(); // mode was verified earlier, so this is safe - if cap.at(1).unwrap() != "" { + if match cap.at(1) { + Some("") | None => false, + _ => true, + } { // symbolic let mut levels = cap.at(2).unwrap(); if levels.len() == 0 { @@ -293,7 +304,7 @@ fn chmod_file(file: &Path, name: &str, changes: bool, quiet: bool, verbose: bool if unsafe { libc::chmod(path.as_ptr(), fperm) } == 0 { // TODO: see above } else { - show_error!("{}", io::Error::last_os_error()); + show_error!("{}", Error::last_os_error()); return Err(1); } } diff --git a/src/chroot/chroot.rs b/src/chroot/chroot.rs index 75c364b98..675592b9e 100644 --- a/src/chroot/chroot.rs +++ b/src/chroot/chroot.rs @@ -1,5 +1,5 @@ #![crate_name = "chroot"] -#![feature(collections, core, old_io, os, old_path, rustc_private, std_misc)] +#![feature(collections, rustc_private, path_ext)] /* * This file is part of the uutils coreutils package. @@ -15,11 +15,12 @@ extern crate libc; use getopts::{optflag, optopt, getopts, usage}; use c_types::{get_pw_from_args, get_group}; -use libc::funcs::posix88::unistd::{execvp, setuid, setgid}; +use libc::funcs::posix88::unistd::{execvp, setgid, setuid}; use std::ffi::{CStr, CString}; +use std::fs::PathExt; +use std::io::Write; use std::iter::FromIterator; use std::path::Path; -use std::env; #[path = "../common/util.rs"] #[macro_use] mod util; #[path = "../common/c_types.rs"] mod c_types; @@ -59,25 +60,25 @@ pub fn uumain(args: Vec) -> i32 { Ok(m) => m, Err(f) => { show_error!("{}", f); - help_menu(program.as_slice(), &options); + help_menu(program, &options); return 1 } }; if opts.opt_present("V") { version(); return 0 } - if opts.opt_present("h") { help_menu(program.as_slice(), &options); return 0 } + if opts.opt_present("h") { help_menu(program, &options); return 0 } if opts.free.len() == 0 { println!("Missing operand: NEWROOT"); - println!("Try `{} --help` for more information.", program.as_slice()); + println!("Try `{} --help` for more information.", program); return 1 } let default_shell: &'static str = "/bin/sh"; let default_option: &'static str = "-i"; - let user_shell = env::var("SHELL"); + let user_shell = std::env::var("SHELL"); - let newroot = Path::new(opts.free[0].as_slice()); + let newroot = Path::new(&opts.free[0][..]); if !newroot.is_dir() { crash!(1, "cannot change root directory to `{}`: no such directory", newroot.display()); } @@ -85,12 +86,12 @@ pub fn uumain(args: Vec) -> i32 { let command: Vec<&str> = match opts.free.len() { 1 => { let shell: &str = match user_shell { - None => default_shell, - Some(ref s) => s.as_slice() + Err(_) => default_shell, + Ok(ref s) => &s[..], }; vec!(shell, default_option) } - _ => opts.free[1..opts.free.len()].iter().map(|x| x.as_slice()).collect() + _ => opts.free[1..opts.free.len()].iter().map(|x| &x[..]).collect() }; set_context(&newroot, &opts); @@ -110,32 +111,32 @@ fn set_context(root: &Path, options: &getopts::Matches) { let groups_str = options.opt_str("groups").unwrap_or_default(); let userspec = match userspec_str { Some(ref u) => { - let s: Vec<&str> = u.as_slice().split(':').collect(); + let s: Vec<&str> = u.split(':').collect(); if s.len() != 2 { - crash!(1, "invalid userspec: `{}`", u.as_slice()) + crash!(1, "invalid userspec: `{}`", u) }; s } None => Vec::new() }; - let user = if userspec.is_empty() { user_str.as_slice() } else { userspec[0].as_slice() }; - let group = if userspec.is_empty() { group_str.as_slice() } else { userspec[1].as_slice() }; + let user = if userspec.is_empty() { &user_str[..] } else { &userspec[0][..] }; + let group = if userspec.is_empty() { &group_str[..] } else { &userspec[1][..] }; enter_chroot(root); - set_groups_from_str(groups_str.as_slice()); - set_main_group(group); - set_user(user); + set_groups_from_str(&groups_str[..]); + set_main_group(&group[..]); + set_user(&user[..]); } fn enter_chroot(root: &Path) { let root_str = root.display(); - env::set_current_dir(root).unwrap(); + std::env::set_current_dir(root).unwrap(); let err = unsafe { - chroot(CString::new(b".").unwrap().as_bytes_with_nul().as_ptr() as *const libc::c_char) + chroot(CString::new(".".as_bytes()).unwrap().as_bytes_with_nul().as_ptr() as *const libc::c_char) }; if err != 0 { - crash!(1, "cannot chroot to {}: {}", root_str, strerror(err).as_slice()) + crash!(1, "cannot chroot to {}: {}", root_str, strerror(err)) }; } @@ -147,7 +148,7 @@ fn set_main_group(group: &str) { }; let err = unsafe { setgid(group_id) }; if err != 0 { - crash!(1, "cannot set gid to {}: {}", group_id, strerror(err).as_slice()) + crash!(1, "cannot set gid to {}: {}", group_id, strerror(err)) } } } @@ -156,7 +157,7 @@ fn set_main_group(group: &str) { fn set_groups(groups: Vec) -> libc::c_int { unsafe { setgroups(groups.len() as libc::c_int, - groups.as_slice().as_ptr()) + groups.as_ptr()) } } @@ -164,7 +165,7 @@ fn set_groups(groups: Vec) -> libc::c_int { fn set_groups(groups: Vec) -> libc::c_int { unsafe { setgroups(groups.len() as libc::size_t, - groups.as_slice().as_ptr()) + groups.as_ptr()) } } @@ -179,7 +180,7 @@ fn set_groups_from_str(groups: &str) { ); let err = set_groups(groups_vec); if err != 0 { - crash!(1, "cannot set groups: {}", strerror(err).as_slice()) + crash!(1, "cannot set groups: {}", strerror(err)) } } } @@ -189,7 +190,7 @@ fn set_user(user: &str) { let user_id = get_pw_from_args(&vec!(String::from_str(user))).unwrap().pw_uid; let err = unsafe { setuid(user_id as libc::uid_t) }; if err != 0 { - crash!(1, "cannot set user to {}: {}", user, strerror(err).as_slice()) + crash!(1, "cannot set user to {}: {}", user, strerror(err)) } } } diff --git a/src/common/c_types.rs b/src/common/c_types.rs index 0e2bcf76c..8ff1cc8c9 100644 --- a/src/common/c_types.rs +++ b/src/common/c_types.rs @@ -16,10 +16,10 @@ use self::libc::int32_t; use self::libc::funcs::posix88::unistd::getgroups; use std::ffi::{CStr, CString}; +use std::io::{Error, Write}; use std::iter::repeat; use std::vec::Vec; -use std::os; use std::ptr::{null_mut, read}; #[cfg(any(target_os = "macos", target_os = "freebsd"))] @@ -49,7 +49,7 @@ pub struct c_passwd { pub pw_shell: *const c_char, } -impl Copy for c_passwd {} +//impl Copy for c_passwd {} #[cfg(any(target_os = "macos", target_os = "freebsd"))] #[repr(C)] @@ -72,7 +72,7 @@ pub struct utsname { pub domainame: [c_char; 65] } -impl Copy for utsname {} +//impl Copy for utsname {} #[repr(C)] pub struct c_group { @@ -82,7 +82,7 @@ pub struct c_group { pub gr_mem: *const *const c_char, // member list } -impl Copy for c_group {} +//impl Copy for c_group {} #[repr(C)] pub struct c_tm { @@ -97,7 +97,7 @@ pub struct c_tm { pub tm_isdst: c_int /* daylight saving time */ } -impl Copy for c_tm {} +//impl Copy for c_tm {} extern { pub fn getpwuid(uid: uid_t) -> *const c_passwd; @@ -117,7 +117,7 @@ extern { pub fn get_pw_from_args(free: &Vec) -> Option { if free.len() == 1 { - let username = free[0].as_slice(); + let username = &free[0][..]; // Passed user as id if username.chars().all(|c| c.is_digit(10)) { @@ -202,13 +202,13 @@ unsafe fn get_group_list_internal(name: *const c_char, gid: gid_t, groups: *mut pub fn get_groups() -> Result, i32> { let ngroups = unsafe { getgroups(0, null_mut()) }; if ngroups == -1 { - return Err(os::errno()); + return Err(Error::last_os_error().raw_os_error().unwrap()) } let mut groups : Vec= repeat(0).take(ngroups as usize).collect(); let ngroups = unsafe { getgroups(ngroups, groups.as_mut_ptr()) }; if ngroups == -1 { - Err(os::errno()) + Err(Error::last_os_error().raw_os_error().unwrap()) } else { groups.truncate(ngroups as usize); Ok(groups)