Skip to content
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

exec functions #76

Closed
wants to merge 3 commits into from
Closed

exec functions #76

wants to merge 3 commits into from

Conversation

sajattack
Copy link
Contributor

@sajattack sajattack commented Mar 13, 2018

This isn't really ready for merge yet but I want to open this up for discussion. In issue #64, it was mentioned that we don't want C functions in our header files, but we need some intermediary C to interact with va_lists and char**s. I tried to implement execvp without header C, as you will see commented out, but couldn't get it working. I'm open to suggestions.

@ids1024
Copy link
Contributor

ids1024 commented Mar 14, 2018

we need some intermediary C to interact with va_lists and char**s.

char** certainly is possible to deal with in Rust, though it can be awkward. There is however, not currently a standard way to implement C variadic functions (it looks like they do plan to add support for that, though).

The va_list crate which relibc already depends on seems to make it possible to implement variadic functions (looking at the example in their documentation).

@sajattack
Copy link
Contributor Author

All the variadic functions that have been implemented so far did it without the use of the va_list crate, so I just followed along.

Copy link
Contributor

@dlrobertson dlrobertson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Failing fmt check.
  • nit: in your C for loops
    • spaces around = and <
    • could you add braces to the for loop?

argv[i] = va_arg(ap, char *);
argv[i] = NULL;
va_end(ap);
return _execl(path, argv);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: musl calls execv here.

}
}

int execlp(const char* file, const char* argv0, ...) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check out the implementation in musl. You shouldn't assume that a box has /bin/sh here. This is more like an implementation of system.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea what's going on in the musl implementation of execvp

}
}

int execvp(const char* file, char *const _argv[]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

while !(*env).is_null() {
let slice = c_str(*env);
// Should always contain a =, but worth checking
if let Some(sep) = slice.iter().position(|&c| c == b'=') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will also probably want to make sure that the value isn't just an = or one side isn't empty.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is true, empty env values are expected

// unimplemented!();
// }
#[no_mangle]
pub extern "C" fn _execl(path: *const c_char, args: *const *mut c_char) -> c_int {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use execv like musl. You can remove this function. It has the same signature.

}

#[no_mangle]
pub extern "C" fn _execle(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same signature as execve. Just use execve in the C implementation of execle.

argv[i] = va_arg(ap, char *);
envp = va_arg(ap, char **);
va_end(ap);
return _execle(path, argv, envp);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use execve here.

}
/*
*#[no_mangle]
*pub extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) -> c_int {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just remove this if you're going to comment it out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was hoping someone could have a look at it and see a way to fix it.

@sajattack
Copy link
Contributor Author

I'm leaving execvp and execlp for someone smarter.

@dlrobertson dlrobertson force-pushed the unistd branch 2 times, most recently from afee3d3 to 06efe08 Compare March 22, 2018 16:17
@@ -54,6 61,10 @@ pub unsafe fn c_str_n(s: *const c_char, n: usize) -> &'static [u8] {
slice::from_raw_parts(s as *const u8, size as usize)
}

pub unsafe fn cstr_from_bytes_with_nul_unchecked(bytes: &[u8]) -> *const c_char {
&*(bytes as *const [u8] as *const c_char)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be bytes.as_ptr() as *const c_char?

But this function seems to be unused currently anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ids1024 I took this straight from CString.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The &* is only needed in CStr because that function returns a reference, not a pointer.

And it looks like the use of a pointer to a slice is because of the non-optimal way CStr is defined:

pub struct CStr {
    // FIXME: this should not be represented with a DST slice but rather with
    //        just a raw `c_char` along with some form of marker to make
    //        this an unsized type. Essentially `sizeof(&CStr)` should be the
    //        same as `sizeof(&c_char)` but `CStr` should be an unsized type.
    inner: [c_char]
}

Using the cast as *const [u8] as *const c_char may work, but I think that's potentially undefined behavior. as_ptr() exists for this purpose.

Implement execve, execl, and execv and implement setuid and setgid.

Co-authored-by: Dan Robertson <[email protected]>
@@ -62,7 62,7 @@ pub unsafe fn c_str_n(s: *const c_char, n: usize) -> &'static [u8] {
}

pub unsafe fn cstr_from_bytes_with_nul_unchecked(bytes: &[u8]) -> *const c_char {
&*(bytes as *const [u8] as *const c_char)
bytes.as_ptr() as *const c_char)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You accidentally left in the close-paren there.

@sajattack sajattack closed this Feb 16, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants