1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-31 04:57:45 +00:00

Merge pull request #545 from kwantam/master

quick Makefile tweak ; update chmod ; update chroot
This commit is contained in:
Heather 2015-04-26 23:37:28 +03:00
commit 0de3e06d46
4 changed files with 76 additions and 58 deletions

View file

@ -183,7 +183,13 @@ endef
DEPLIBS := libc DEPLIBS := libc
DEPPLUGS := DEPPLUGS :=
# now, add in deps in src/utilname/deps.mk # 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 # uniqify deps
DEPLIBS := $(sort $(DEPLIBS)) DEPLIBS := $(sort $(DEPLIBS))
DEPPLUGS := $(sort $(DEPPLUGS)) DEPPLUGS := $(sort $(DEPPLUGS))
@ -248,8 +254,8 @@ endef
# Test exe built rules # Test exe built rules
define TEST_BUILD define TEST_BUILD
test_$(1): $(TEMPDIR)/$(1)/$(1)_test $(BUILDDIR)/$(1) test_$(1): $(BUILDDIR)/$(1) $(TEMPDIR)/$(1)/$(1)_test
$(call command,cp $(BUILDDIR)/$(1) $(TEMPDIR)/$(1) && cd $(TEMPDIR)/$(1) && $$<) $(call command,cp $(BUILDDIR)/$(1) $(TEMPDIR)/$(1) && cd $(TEMPDIR)/$(1) && $(TEMPDIR)/$(1)/$(1)_test)
$(TEMPDIR)/$(1)/$(1)_test: $(TESTDIR)/$(1).rs | $(TEMPDIR)/$(1) $(TEMPDIR)/$(1)/$(1)_test: $(TESTDIR)/$(1).rs | $(TEMPDIR)/$(1)
$(call command,$(RUSTC) $(RUSTCTESTFLAGS) $(DEP_EXTERN) --test -o $$@ $$<) $(call command,$(RUSTC) $(RUSTCTESTFLAGS) $(DEP_EXTERN) --test -o $$@ $$<)

View file

@ -1,5 +1,5 @@
#![crate_name = "chmod"] #![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. * This file is part of the uutils coreutils package.
@ -19,15 +19,11 @@ extern crate libc;
extern crate regex; extern crate regex;
use std::ffi::CString; use std::ffi::CString;
use std::fs; use std::fs::{self, PathExt};
use std::io;
use std::io::Write;
use std::mem;
use std::u32;
use std::path::Path; use std::path::Path;
use std::fs::PathExt; use std::io::{Error, Write};
use std::mem;
use regex::Regex; use regex::Regex;
use libc::types::os::arch::posix01;
#[path = "../common/util.rs"] #[path = "../common/util.rs"]
#[macro_use] #[macro_use]
@ -51,7 +47,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
getopts::optflag("V", "version", "output version information and exit") 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 // 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, Ok(m) => m,
Err(f) => { Err(f) => {
crash!(1, "{}", f) crash!(1, "{}", f)
@ -69,7 +65,7 @@ Usage:
Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.", Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.",
name = NAME, version = VERSION, program = program, name = NAME, version = VERSION, program = program,
usage = getopts::usage("Change the mode of each FILE to MODE. \ 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)); each FILE to that of RFILE.", &opts));
} else if matches.opt_present("version") { } else if matches.opt_present("version") {
println!("{} v{}", NAME, 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 preserve_root = matches.opt_present("preserve-root");
let recursive = matches.opt_present("recursive"); let recursive = matches.opt_present("recursive");
let fmode = matches.opt_str("reference").and_then(|fref| { 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) }; let statres = unsafe { libc::stat(fref.as_ptr() as *const i8, &mut stat as *mut libc::stat) };
if statres == 0 { if statres == 0 {
Some(stat.st_mode) Some(stat.st_mode)
} else { } else {
crash!(1, "{}", io::Error::last_os_error()) crash!(1, "{}", Error::last_os_error())
} }
}); });
let cmode = let cmode =
if fmode.is_none() { if fmode.is_none() {
let mode = matches.free.remove(0); let mode = matches.free.remove(0);
match verify_mode(mode.as_ref()) { match verify_mode(&mode[..]) {
Ok(_) => Some(mode), Ok(_) => Some(mode),
Err(f) => { Err(f) => {
show_error!("{}", f); show_error!("{}", f);
@ -153,7 +149,7 @@ fn chmod(files: Vec<String>, changes: bool, quiet: bool, verbose: bool, preserve
let mut r = Ok(()); let mut r = Ok(());
for filename in files.iter() { for filename in files.iter() {
let filename = filename.as_ref(); let filename = &filename[..];
let file = Path::new(filename); let file = Path::new(filename);
if file.exists() { if file.exists() {
if file.is_dir() { if file.is_dir() {
@ -165,7 +161,19 @@ fn chmod(files: Vec<String>, changes: bool, quiet: bool, verbose: bool, preserve
crash!(1, "{}", f.to_string()); 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); r = chmod_file(&file, filename, changes, quiet, verbose, fmode, cmode).and(r);
} }
} else { } else {
@ -186,31 +194,34 @@ fn chmod(files: Vec<String>, changes: bool, quiet: bool, verbose: bool, preserve
} }
fn chmod_file(file: &Path, name: &str, changes: bool, quiet: bool, verbose: bool, fmode: Option<libc::mode_t>, cmode: Option<&String>) -> Result<(), i32> { fn chmod_file(file: &Path, name: &str, changes: bool, quiet: bool, verbose: bool, fmode: Option<libc::mode_t>, cmode: Option<&String>) -> Result<(), i32> {
let path = CString::new(name).unwrap(); let path = CString::new(name).unwrap_or_else(|e| panic!("{}", e));
match fmode { match fmode {
Some(mode) => { Some(mode) => {
if unsafe { libc::chmod(path.as_ptr(), mode) } == 0 { if unsafe { libc::chmod(path.as_ptr(), mode) } == 0 {
// TODO: handle changes, quiet, and verbose // TODO: handle changes, quiet, and verbose
} else { } else {
show_error!("{}", io::Error::last_os_error()); show_error!("{}", Error::last_os_error());
return Err(1); return Err(1);
} }
} }
None => { None => {
// TODO: make the regex processing occur earlier (i.e. once in the main function) // 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]+)$"); 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 statres = unsafe { libc::stat(path.as_ptr(), &mut stat as *mut libc::stat) };
let mut fperm = let mut fperm =
if statres == 0 { if statres == 0 {
stat.st_mode stat.st_mode
} else { } else {
show_error!("{}", io::Error::last_os_error()); show_error!("{}", Error::last_os_error());
return Err(1); return Err(1);
}; };
for mode in cmode.unwrap().split(',') { // cmode is guaranteed to be Some in this case 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 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 // symbolic
let mut levels = cap.at(2).unwrap(); let mut levels = cap.at(2).unwrap();
if levels.len() == 0 { 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 { if unsafe { libc::chmod(path.as_ptr(), fperm) } == 0 {
// TODO: see above // TODO: see above
} else { } else {
show_error!("{}", io::Error::last_os_error()); show_error!("{}", Error::last_os_error());
return Err(1); return Err(1);
} }
} }

View file

@ -1,5 +1,5 @@
#![crate_name = "chroot"] #![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. * This file is part of the uutils coreutils package.
@ -15,11 +15,12 @@ extern crate libc;
use getopts::{optflag, optopt, getopts, usage}; use getopts::{optflag, optopt, getopts, usage};
use c_types::{get_pw_from_args, get_group}; 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::ffi::{CStr, CString};
use std::fs::PathExt;
use std::io::Write;
use std::iter::FromIterator; use std::iter::FromIterator;
use std::path::Path; use std::path::Path;
use std::env;
#[path = "../common/util.rs"] #[macro_use] mod util; #[path = "../common/util.rs"] #[macro_use] mod util;
#[path = "../common/c_types.rs"] mod c_types; #[path = "../common/c_types.rs"] mod c_types;
@ -59,25 +60,25 @@ pub fn uumain(args: Vec<String>) -> i32 {
Ok(m) => m, Ok(m) => m,
Err(f) => { Err(f) => {
show_error!("{}", f); show_error!("{}", f);
help_menu(program.as_slice(), &options); help_menu(program, &options);
return 1 return 1
} }
}; };
if opts.opt_present("V") { version(); return 0 } 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 { if opts.free.len() == 0 {
println!("Missing operand: NEWROOT"); println!("Missing operand: NEWROOT");
println!("Try `{} --help` for more information.", program.as_slice()); println!("Try `{} --help` for more information.", program);
return 1 return 1
} }
let default_shell: &'static str = "/bin/sh"; let default_shell: &'static str = "/bin/sh";
let default_option: &'static str = "-i"; 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() { if !newroot.is_dir() {
crash!(1, "cannot change root directory to `{}`: no such directory", newroot.display()); crash!(1, "cannot change root directory to `{}`: no such directory", newroot.display());
} }
@ -85,12 +86,12 @@ pub fn uumain(args: Vec<String>) -> i32 {
let command: Vec<&str> = match opts.free.len() { let command: Vec<&str> = match opts.free.len() {
1 => { 1 => {
let shell: &str = match user_shell { let shell: &str = match user_shell {
None => default_shell, Err(_) => default_shell,
Some(ref s) => s.as_slice() Ok(ref s) => &s[..],
}; };
vec!(shell, default_option) 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); 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 groups_str = options.opt_str("groups").unwrap_or_default();
let userspec = match userspec_str { let userspec = match userspec_str {
Some(ref u) => { Some(ref u) => {
let s: Vec<&str> = u.as_slice().split(':').collect(); let s: Vec<&str> = u.split(':').collect();
if s.len() != 2 { if s.len() != 2 {
crash!(1, "invalid userspec: `{}`", u.as_slice()) crash!(1, "invalid userspec: `{}`", u)
}; };
s s
} }
None => Vec::new() None => Vec::new()
}; };
let user = if userspec.is_empty() { user_str.as_slice() } else { userspec[0].as_slice() }; let user = if userspec.is_empty() { &user_str[..] } else { &userspec[0][..] };
let group = if userspec.is_empty() { group_str.as_slice() } else { userspec[1].as_slice() }; let group = if userspec.is_empty() { &group_str[..] } else { &userspec[1][..] };
enter_chroot(root); enter_chroot(root);
set_groups_from_str(groups_str.as_slice()); set_groups_from_str(&groups_str[..]);
set_main_group(group); set_main_group(&group[..]);
set_user(user); set_user(&user[..]);
} }
fn enter_chroot(root: &Path) { fn enter_chroot(root: &Path) {
let root_str = root.display(); let root_str = root.display();
env::set_current_dir(root).unwrap(); std::env::set_current_dir(root).unwrap();
let err = unsafe { 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 { 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) }; let err = unsafe { setgid(group_id) };
if err != 0 { 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::gid_t>) -> libc::c_int { fn set_groups(groups: Vec<libc::gid_t>) -> libc::c_int {
unsafe { unsafe {
setgroups(groups.len() as libc::c_int, 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::gid_t>) -> libc::c_int {
fn set_groups(groups: Vec<libc::gid_t>) -> libc::c_int { fn set_groups(groups: Vec<libc::gid_t>) -> libc::c_int {
unsafe { unsafe {
setgroups(groups.len() as libc::size_t, 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); let err = set_groups(groups_vec);
if err != 0 { 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 user_id = get_pw_from_args(&vec!(String::from_str(user))).unwrap().pw_uid;
let err = unsafe { setuid(user_id as libc::uid_t) }; let err = unsafe { setuid(user_id as libc::uid_t) };
if err != 0 { if err != 0 {
crash!(1, "cannot set user to {}: {}", user, strerror(err).as_slice()) crash!(1, "cannot set user to {}: {}", user, strerror(err))
} }
} }
} }

View file

@ -16,10 +16,10 @@ use self::libc::int32_t;
use self::libc::funcs::posix88::unistd::getgroups; use self::libc::funcs::posix88::unistd::getgroups;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::io::{Error, Write};
use std::iter::repeat; use std::iter::repeat;
use std::vec::Vec; use std::vec::Vec;
use std::os;
use std::ptr::{null_mut, read}; use std::ptr::{null_mut, read};
#[cfg(any(target_os = "macos", target_os = "freebsd"))] #[cfg(any(target_os = "macos", target_os = "freebsd"))]
@ -49,7 +49,7 @@ pub struct c_passwd {
pub pw_shell: *const c_char, pub pw_shell: *const c_char,
} }
impl Copy for c_passwd {} //impl Copy for c_passwd {}
#[cfg(any(target_os = "macos", target_os = "freebsd"))] #[cfg(any(target_os = "macos", target_os = "freebsd"))]
#[repr(C)] #[repr(C)]
@ -72,7 +72,7 @@ pub struct utsname {
pub domainame: [c_char; 65] pub domainame: [c_char; 65]
} }
impl Copy for utsname {} //impl Copy for utsname {}
#[repr(C)] #[repr(C)]
pub struct c_group { pub struct c_group {
@ -82,7 +82,7 @@ pub struct c_group {
pub gr_mem: *const *const c_char, // member list pub gr_mem: *const *const c_char, // member list
} }
impl Copy for c_group {} //impl Copy for c_group {}
#[repr(C)] #[repr(C)]
pub struct c_tm { pub struct c_tm {
@ -97,7 +97,7 @@ pub struct c_tm {
pub tm_isdst: c_int /* daylight saving time */ pub tm_isdst: c_int /* daylight saving time */
} }
impl Copy for c_tm {} //impl Copy for c_tm {}
extern { extern {
pub fn getpwuid(uid: uid_t) -> *const c_passwd; pub fn getpwuid(uid: uid_t) -> *const c_passwd;
@ -117,7 +117,7 @@ extern {
pub fn get_pw_from_args(free: &Vec<String>) -> Option<c_passwd> { pub fn get_pw_from_args(free: &Vec<String>) -> Option<c_passwd> {
if free.len() == 1 { if free.len() == 1 {
let username = free[0].as_slice(); let username = &free[0][..];
// Passed user as id // Passed user as id
if username.chars().all(|c| c.is_digit(10)) { 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<Vec<gid_t>, i32> { pub fn get_groups() -> Result<Vec<gid_t>, i32> {
let ngroups = unsafe { getgroups(0, null_mut()) }; let ngroups = unsafe { getgroups(0, null_mut()) };
if ngroups == -1 { if ngroups == -1 {
return Err(os::errno()); return Err(Error::last_os_error().raw_os_error().unwrap())
} }
let mut groups : Vec<gid_t>= repeat(0).take(ngroups as usize).collect(); let mut groups : Vec<gid_t>= repeat(0).take(ngroups as usize).collect();
let ngroups = unsafe { getgroups(ngroups, groups.as_mut_ptr()) }; let ngroups = unsafe { getgroups(ngroups, groups.as_mut_ptr()) };
if ngroups == -1 { if ngroups == -1 {
Err(os::errno()) Err(Error::last_os_error().raw_os_error().unwrap())
} else { } else {
groups.truncate(ngroups as usize); groups.truncate(ngroups as usize);
Ok(groups) Ok(groups)