Add argc and argv support
This commit is contained in:
parent
ae063cbf90
commit
ad704c421f
@ -7,7 +7,7 @@ enclave {
|
||||
|
||||
trusted {
|
||||
/* define ECALLs here. */
|
||||
public int libos_boot([in, string] const char* executable_path);
|
||||
public int libos_boot([in, string] const char* executable_path, [user_check] char** argv);
|
||||
public int libos_run(void);
|
||||
};
|
||||
|
||||
|
82
src/libos/src/entry.rs
Normal file
82
src/libos/src/entry.rs
Normal file
@ -0,0 +1,82 @@
|
||||
use super::{*};
|
||||
use util::mem_util::from_untrusted::*;
|
||||
use std::ffi::{CStr, CString, OsString};
|
||||
use std::path::{Path};
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn libos_boot(path_buf: *const c_char, argv: *const *const c_char) -> i32 {
|
||||
let (path, args) = match parse_arguments(path_buf, argv) {
|
||||
Ok(path_and_args) => {
|
||||
path_and_args
|
||||
},
|
||||
Err(_) => {
|
||||
return EXIT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
};
|
||||
|
||||
let _ = backtrace::enable_backtrace("libocclum.signed.so", PrintFormat::Short);
|
||||
panic::catch_unwind(||{
|
||||
backtrace::__rust_begin_short_backtrace(||{
|
||||
match do_boot(&path, &args) {
|
||||
Ok(()) => 0,
|
||||
Err(err) => EXIT_STATUS_INTERNAL_ERROR,
|
||||
}
|
||||
})
|
||||
}).unwrap_or(EXIT_STATUS_INTERNAL_ERROR)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn libos_run() -> i32 {
|
||||
let _ = backtrace::enable_backtrace("libocclum.signed.so", PrintFormat::Short);
|
||||
panic::catch_unwind(||{
|
||||
backtrace::__rust_begin_short_backtrace(||{
|
||||
match do_run() {
|
||||
Ok(exit_status) => exit_status,
|
||||
Err(err) => EXIT_STATUS_INTERNAL_ERROR,
|
||||
}
|
||||
})
|
||||
}).unwrap_or(EXIT_STATUS_INTERNAL_ERROR)
|
||||
}
|
||||
|
||||
// Use 127 as a special value to indicate internal error from libos, not from
|
||||
// user programs, although it is completely ok for a user program to return 127.
|
||||
const EXIT_STATUS_INTERNAL_ERROR : i32 = 127;
|
||||
|
||||
fn parse_arguments(path_buf: *const c_char, argv: *const *const c_char)
|
||||
-> Result<(String, Vec<CString>), Error>
|
||||
{
|
||||
let path_string = {
|
||||
let path_cstring = clone_cstring_safely(path_buf)?;
|
||||
path_cstring.to_string_lossy().into_owned()
|
||||
};
|
||||
let program_cstring = {
|
||||
let program_osstr= Path::new(&path_string).file_name()
|
||||
.ok_or_else(|| Error::new(Errno::EINVAL, "Invalid path"))?;
|
||||
let program_str = program_osstr.to_str()
|
||||
.ok_or_else(|| Error::new(Errno::EINVAL, "Invalid path"))?;
|
||||
CString::new(program_str)
|
||||
.or_else(|_| errno!(EINVAL, "Invalid path"))?
|
||||
};
|
||||
|
||||
let mut args = clone_cstrings_safely(argv)?;
|
||||
args.insert(0, program_cstring);
|
||||
Ok((path_string, args))
|
||||
}
|
||||
|
||||
// TODO: make sure do_boot can only be called once
|
||||
fn do_boot(path_str: &str, argv: &Vec<CString>) -> Result<(), Error> {
|
||||
util::mpx_util::mpx_enable()?;
|
||||
|
||||
let envp = std::vec::Vec::new();
|
||||
let file_actions = Vec::new();
|
||||
let parent = &process::IDLE_PROCESS;
|
||||
process::do_spawn(&path_str, argv, &envp, &file_actions, parent)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: make sure do_run() cannot be called after do_boot()
|
||||
fn do_run() -> Result<i32, Error> {
|
||||
let exit_status = process::run_task()?;
|
||||
Ok(exit_status)
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use super::*;
|
||||
use util::{new_ring_buf, RingBufReader, RingBufWriter};
|
||||
use util::ring_buf::{*};
|
||||
|
||||
// TODO: Use Waiter and WaitQueue infrastructure to sleep when blocking
|
||||
|
||||
@ -13,13 +13,13 @@ pub struct Pipe {
|
||||
|
||||
impl Pipe {
|
||||
pub fn new() -> Result<Pipe, Error> {
|
||||
let (reader, writer) = new_ring_buf(PIPE_BUF_SIZE);
|
||||
let mut ring_buf = RingBuf::new(PIPE_BUF_SIZE);
|
||||
Ok(Pipe {
|
||||
reader: PipeReader {
|
||||
inner: SgxMutex::new(reader),
|
||||
inner: SgxMutex::new(ring_buf.reader),
|
||||
},
|
||||
writer: PipeWriter {
|
||||
inner: SgxMutex::new(writer),
|
||||
inner: SgxMutex::new(ring_buf.writer),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ use sgx_trts::libc;
|
||||
|
||||
#[macro_use]
|
||||
mod prelude;
|
||||
mod entry;
|
||||
mod errno;
|
||||
mod fs;
|
||||
mod process;
|
||||
@ -36,58 +37,7 @@ mod time;
|
||||
|
||||
use prelude::*;
|
||||
|
||||
/// Export system calls
|
||||
// Export system calls
|
||||
pub use syscall::*;
|
||||
|
||||
// TODO: return meaningful exit code
|
||||
#[no_mangle]
|
||||
pub extern "C" fn libos_boot(path_buf: *const i8) -> i32 {
|
||||
let path_str = unsafe {
|
||||
CStr::from_ptr(path_buf).to_string_lossy().into_owned()
|
||||
};
|
||||
let _ = backtrace::enable_backtrace("libocclum.signed.so", PrintFormat::Short);
|
||||
panic::catch_unwind(||{
|
||||
backtrace::__rust_begin_short_backtrace(||{
|
||||
match do_boot(&path_str) {
|
||||
Ok(()) => 0,
|
||||
Err(err) => EXIT_STATUS_INTERNAL_ERROR,
|
||||
}
|
||||
})
|
||||
}).unwrap_or(EXIT_STATUS_INTERNAL_ERROR)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn libos_run() -> i32 {
|
||||
let _ = backtrace::enable_backtrace("libocclum.signed.so", PrintFormat::Short);
|
||||
panic::catch_unwind(||{
|
||||
backtrace::__rust_begin_short_backtrace(||{
|
||||
match do_run() {
|
||||
Ok(exit_status) => exit_status,
|
||||
Err(err) => EXIT_STATUS_INTERNAL_ERROR,
|
||||
}
|
||||
})
|
||||
}).unwrap_or(EXIT_STATUS_INTERNAL_ERROR)
|
||||
}
|
||||
|
||||
// Use 127 as a special value to indicate internal error from libos, not from
|
||||
// user programs, although it is completely ok for a user program to return 127.
|
||||
const EXIT_STATUS_INTERNAL_ERROR : i32 = 127;
|
||||
|
||||
// TODO: make sure do_boot can only be called once
|
||||
fn do_boot(path_str: &str) -> Result<(), Error> {
|
||||
util::mpx_enable()?;
|
||||
|
||||
let argv = std::vec::Vec::new();
|
||||
let envp = std::vec::Vec::new();
|
||||
let file_actions = Vec::new();
|
||||
let parent = &process::IDLE_PROCESS;
|
||||
process::do_spawn(&path_str, &argv, &envp, &file_actions, parent)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: make sure do_run() cannot be called before do_boot()
|
||||
fn do_run() -> Result<i32, Error> {
|
||||
let exit_status = process::run_task()?;
|
||||
Ok(exit_status)
|
||||
}
|
||||
// Export ECalls
|
||||
pub use entry::*;
|
||||
|
@ -7,6 +7,7 @@ use fs::{off_t, FileDesc};
|
||||
use vm::{VMAreaFlags, VMResizeOptions};
|
||||
use process::{pid_t, ChildProcessFilter, FileAction};
|
||||
use time::{timeval_t};
|
||||
use util::mem_util::from_user::{*};
|
||||
// Use the internal syscall wrappers from sgx_tstd
|
||||
//use std::libc_fs as fs;
|
||||
//use std::libc_io as io;
|
||||
@ -17,39 +18,6 @@ pub struct iovec_t {
|
||||
len: size_t,
|
||||
}
|
||||
|
||||
fn check_ptr_from_user<T>(user_ptr: *const T) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_mut_ptr_from_user<T>(user_ptr: *mut T) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_array_from_user<T>(user_buf: *const T, count: usize) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_mut_array_from_user<T>(user_buf: *mut T, count: usize) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clone_cstring_from_user_safely(user_ptr: *const c_char)
|
||||
-> Result<String, Error>
|
||||
{
|
||||
check_ptr_from_user(user_ptr)?;
|
||||
let string = unsafe {
|
||||
CStr::from_ptr(user_ptr).to_string_lossy().into_owned()
|
||||
};
|
||||
Ok(string)
|
||||
}
|
||||
|
||||
fn clone_cstrings_from_user_safely(user_ptr: *const *const c_char)
|
||||
-> Result<Vec<CString>, Error>
|
||||
{
|
||||
let cstrings = Vec::new();
|
||||
Ok(cstrings)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This Rust-version of fdop correspond to the C-version one in Occlum.
|
||||
@ -73,14 +41,14 @@ pub struct FdOp {
|
||||
path: *const u8,
|
||||
}
|
||||
|
||||
fn clone_file_actions_from_user_safely(fdop_ptr: *const FdOp)
|
||||
fn clone_file_actions_safely(fdop_ptr: *const FdOp)
|
||||
-> Result<Vec<FileAction>, Error>
|
||||
{
|
||||
let mut file_actions = Vec::new();
|
||||
|
||||
let mut fdop_ptr = fdop_ptr;
|
||||
while fdop_ptr != ptr::null() {
|
||||
check_ptr_from_user(fdop_ptr)?;
|
||||
check_ptr(fdop_ptr)?;
|
||||
let fdop = unsafe { &*fdop_ptr };
|
||||
|
||||
let file_action = match fdop.cmd {
|
||||
@ -113,11 +81,11 @@ fn do_spawn(child_pid_ptr: *mut c_uint,
|
||||
)
|
||||
-> Result<(), Error>
|
||||
{
|
||||
check_mut_ptr_from_user(child_pid_ptr)?;
|
||||
let path = clone_cstring_from_user_safely(path)?;
|
||||
let argv = clone_cstrings_from_user_safely(argv)?;
|
||||
let envp = clone_cstrings_from_user_safely(envp)?;
|
||||
let file_actions = clone_file_actions_from_user_safely(fdop_list)?;
|
||||
check_mut_ptr(child_pid_ptr)?;
|
||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
||||
let argv = clone_cstrings_safely(argv)?;
|
||||
let envp = clone_cstrings_safely(envp)?;
|
||||
let file_actions = clone_file_actions_safely(fdop_list)?;
|
||||
let parent = process::get_current();
|
||||
|
||||
let child_pid = process::do_spawn(&path, &argv, &envp, &file_actions, &parent)?;
|
||||
@ -133,7 +101,7 @@ fn do_read(fd: c_int, buf: *mut c_void, size: size_t)
|
||||
let safe_buf = {
|
||||
let buf = buf as *mut u8;
|
||||
let size = size as usize;
|
||||
check_mut_array_from_user(buf, size)?;
|
||||
check_mut_array(buf, size)?;
|
||||
unsafe { std::slice::from_raw_parts_mut(buf, size) }
|
||||
};
|
||||
fs::do_read(fd, safe_buf)
|
||||
@ -146,7 +114,7 @@ fn do_write(fd: c_int, buf: *const c_void, size: size_t)
|
||||
let safe_buf = {
|
||||
let buf = buf as *mut u8;
|
||||
let size = size as usize;
|
||||
check_array_from_user(buf, size)?;
|
||||
check_array(buf, size)?;
|
||||
unsafe { std::slice::from_raw_parts(buf, size) }
|
||||
};
|
||||
fs::do_write(fd, safe_buf)
|
||||
@ -164,7 +132,7 @@ fn do_writev(fd: c_int, iov: *const iovec_t, count: c_int)
|
||||
count as usize
|
||||
};
|
||||
|
||||
check_array_from_user(iov, count);
|
||||
check_array(iov, count);
|
||||
let bufs_vec = {
|
||||
let mut bufs_vec = Vec::with_capacity(count);
|
||||
for iov_i in 0..count {
|
||||
@ -194,7 +162,7 @@ fn do_readv(fd: c_int, iov: *mut iovec_t, count: c_int)
|
||||
count as usize
|
||||
};
|
||||
|
||||
check_array_from_user(iov, count);
|
||||
check_array(iov, count);
|
||||
let mut bufs_vec = {
|
||||
let mut bufs_vec = Vec::with_capacity(count);
|
||||
for iov_i in 0..count {
|
||||
@ -274,7 +242,7 @@ fn do_brk(new_brk_addr: *const c_void) -> Result<*const c_void, Error> {
|
||||
|
||||
fn do_wait4(pid: c_int, _exit_status: *mut c_int) -> Result<pid_t, Error> {
|
||||
if _exit_status != 0 as *mut c_int {
|
||||
check_mut_ptr_from_user(_exit_status)?;
|
||||
check_mut_ptr(_exit_status)?;
|
||||
}
|
||||
|
||||
let child_process_filter = match pid {
|
||||
@ -310,7 +278,7 @@ fn do_wait4(pid: c_int, _exit_status: *mut c_int) -> Result<pid_t, Error> {
|
||||
}
|
||||
|
||||
fn do_pipe2(fds_u: *mut c_int, flags: c_int) -> Result<(), Error> {
|
||||
check_mut_array_from_user(fds_u, 2)?;
|
||||
check_mut_array(fds_u, 2)?;
|
||||
// TODO: how to deal with open flags???
|
||||
let fds = fs::do_pipe2(flags as u32)?;
|
||||
unsafe {
|
||||
@ -321,7 +289,7 @@ fn do_pipe2(fds_u: *mut c_int, flags: c_int) -> Result<(), Error> {
|
||||
}
|
||||
|
||||
fn do_gettimeofday(tv_u: *mut timeval_t) -> Result<(), Error> {
|
||||
check_mut_ptr_from_user(tv_u)?;
|
||||
check_mut_ptr(tv_u)?;
|
||||
let tv = time::do_gettimeofday();
|
||||
unsafe { *tv_u = tv; }
|
||||
Ok(())
|
||||
|
110
src/libos/src/util/mem_util.rs
Normal file
110
src/libos/src/util/mem_util.rs
Normal file
@ -0,0 +1,110 @@
|
||||
use super::*;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::{ptr};
|
||||
|
||||
/// Memory utilities that deals with primitive types passed from user process
|
||||
/// running inside enclave
|
||||
pub mod from_user {
|
||||
use super::*;
|
||||
|
||||
/// Check the user pointer is within the readable memory range of the user process
|
||||
pub fn check_ptr<T>(user_ptr: *const T) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check the mutable user pointer is within the writable memory of the user process
|
||||
pub fn check_mut_ptr<T>(user_ptr: *mut T) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check the readonly array is within the readable memory of the user process
|
||||
pub fn check_array<T>(user_buf: *const T, count: usize) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check the mutable array is within the writable memory of the user process
|
||||
pub fn check_mut_array<T>(user_buf: *mut T, count: usize) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Clone a C-string from the user process safely
|
||||
pub fn clone_cstring_safely(out_ptr: *const c_char)
|
||||
-> Result<CString, Error>
|
||||
{
|
||||
check_ptr(out_ptr)?;
|
||||
// TODO: using from_ptr directly is not safe
|
||||
let cstr = unsafe { CStr::from_ptr(out_ptr) };
|
||||
let cstring = CString::from(cstr);
|
||||
Ok(cstring)
|
||||
}
|
||||
|
||||
/// Clone a C-string array (const char*[]) from the user process safely
|
||||
///
|
||||
/// This array must be ended with a NULL pointer.
|
||||
pub fn clone_cstrings_safely(user_ptr: *const *const c_char)
|
||||
-> Result<Vec<CString>, Error>
|
||||
{
|
||||
let mut cstrings = Vec::new();
|
||||
let mut user_ptr = user_ptr;
|
||||
while user_ptr != ptr::null() {
|
||||
let cstr_ptr = unsafe { *user_ptr };
|
||||
let cstring = clone_cstring_safely(cstr_ptr)?;
|
||||
cstrings.push(cstring);
|
||||
user_ptr = unsafe { user_ptr.offset(1) };
|
||||
}
|
||||
Ok(cstrings)
|
||||
}
|
||||
}
|
||||
|
||||
/// Memory utilities that deals with primitive types passed from outside the enclave
|
||||
pub mod from_untrusted {
|
||||
use super::*;
|
||||
|
||||
/// Check the untrusted pointer is outside the enclave
|
||||
pub fn check_ptr<T>(out_ptr: *const T) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check the untrusted array is outside the enclave
|
||||
pub fn check_array<T>(out_ptr: *const T, count: usize) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Clone a C-string from outside the enclave
|
||||
pub fn clone_cstring_safely(out_ptr: *const c_char)
|
||||
-> Result<CString, Error>
|
||||
{
|
||||
check_ptr(out_ptr)?;
|
||||
// TODO: using from_ptr directly is not safe
|
||||
let cstr = unsafe { CStr::from_ptr(out_ptr) };
|
||||
let cstring = CString::from(cstr);
|
||||
Ok(cstring)
|
||||
}
|
||||
|
||||
/// Clone a C-string array (const char*[]) from outside the enclave
|
||||
///
|
||||
/// This array must be ended with a NULL pointer.
|
||||
pub fn clone_cstrings_safely(out_ptr: *const *const c_char)
|
||||
-> Result<Vec<CString>, Error>
|
||||
{
|
||||
let mut cstrings = Vec::new();
|
||||
if out_ptr == ptr::null() { return Ok(cstrings); }
|
||||
|
||||
let mut out_ptr = out_ptr;
|
||||
loop {
|
||||
check_ptr(out_ptr);
|
||||
let cstr_ptr = {
|
||||
let cstr_ptr = unsafe { *out_ptr };
|
||||
if cstr_ptr == ptr::null() { break; }
|
||||
check_ptr(cstr_ptr);
|
||||
cstr_ptr
|
||||
};
|
||||
let cstring = clone_cstring_safely(cstr_ptr)?;
|
||||
cstrings.push(cstring);
|
||||
|
||||
out_ptr = unsafe { out_ptr.offset(1) };
|
||||
}
|
||||
Ok(cstrings)
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,5 @@
|
||||
use super::*;
|
||||
|
||||
pub use self::mpx_util::{*};
|
||||
pub use self::ring_buf::{RingBufReader, RingBufWriter};
|
||||
pub use self::ring_buf::with_fixed_capacity as new_ring_buf;
|
||||
|
||||
mod mpx_util;
|
||||
mod ring_buf;
|
||||
pub mod mpx_util;
|
||||
pub mod ring_buf;
|
||||
pub mod mem_util;
|
||||
|
@ -4,11 +4,19 @@ use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
|
||||
use std::cmp::{min, max};
|
||||
use std::{ptr};
|
||||
|
||||
pub fn with_fixed_capacity(capacity: usize) -> (RingBufReader, RingBufWriter) {
|
||||
#[derive(Debug)]
|
||||
pub struct RingBuf {
|
||||
pub reader: RingBufReader,
|
||||
pub writer: RingBufWriter,
|
||||
}
|
||||
|
||||
impl RingBuf {
|
||||
pub fn new(capacity: usize) -> RingBuf {
|
||||
let inner = Arc::new(RingBufInner::new(capacity));
|
||||
let reader = RingBufReader { inner: inner.clone() };
|
||||
let writer = RingBufWriter { inner: inner };
|
||||
(reader, writer)
|
||||
RingBuf { reader: reader, writer: writer }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -214,9 +214,9 @@ int SGX_CDECL main(int argc, char *argv[])
|
||||
uint32_t sealed_log_size = 1024;
|
||||
uint8_t sealed_log[1024] = {0};
|
||||
|
||||
if (argc != 2) {
|
||||
printf("ERROR: The expected number of arguments is 1, but given %d\n\n", argc - 1);
|
||||
printf("Usage: pal <path_to_executable>\n");
|
||||
if (argc < 2) {
|
||||
printf("ERROR: at least one argument must be provided\n\n");
|
||||
printf("Usage: pal <executable> <arg1> <arg2>...\n");
|
||||
return -1;
|
||||
}
|
||||
const char* executable_path = argv[1];
|
||||
@ -229,7 +229,7 @@ int SGX_CDECL main(int argc, char *argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
sgx_ret = libos_boot(global_eid, &status, executable_path);
|
||||
sgx_ret = libos_boot(global_eid, &status, executable_path, &argv[2]);
|
||||
if(sgx_ret != SGX_SUCCESS) {
|
||||
print_error_message(sgx_ret);
|
||||
return status;
|
||||
|
@ -1,7 +1,7 @@
|
||||
CUR_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
PROJECT_DIR := $(realpath $(CUR_DIR)/../)
|
||||
|
||||
TEST_SUITES := empty hello_world malloc file getpid spawn pipe time
|
||||
TEST_SUITES := empty argv hello_world malloc file getpid spawn pipe time
|
||||
BUILD_TEST_SUITES := $(TEST_SUITES:%=%)
|
||||
RUN_TEST_SUITES := $(TEST_SUITES:%=test-%)
|
||||
CLEAN_TEST_SUITES := $(TEST_SUITES:%=clean-%)
|
||||
|
14
test/argv/Makefile
Normal file
14
test/argv/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
include ../test_common.mk
|
||||
|
||||
ARGC := 4
|
||||
ARG1 := 1
|
||||
ARG2 := arg2
|
||||
ARG3 := this is a string with spaces
|
||||
|
||||
EXTRA_C_FLAGS := \
|
||||
-DEXPECTED_ARGC=$(ARGC) \
|
||||
-DEXPECTED_ARG1="\"$(ARG1)\"" \
|
||||
-DEXPECTED_ARG2="\"$(ARG2)\"" \
|
||||
-DEXPECTED_ARG3="\"$(ARG3)\""
|
||||
EXTRA_LINK_FLAGS :=
|
||||
BIN_ARGS := "$(ARG1)" "$(ARG2)" "$(ARG3)"
|
30
test/argv/main.c
Normal file
30
test/argv/main.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Expected arguments are given by Makefile throught macro ARGC, ARG1, ARG2 and
|
||||
// ARG3
|
||||
const char* expected_argv[EXPECTED_ARGC] = {
|
||||
"bin.encrypted",
|
||||
EXPECTED_ARG1,
|
||||
EXPECTED_ARG2,
|
||||
EXPECTED_ARG3,
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != EXPECTED_ARGC) {
|
||||
printf("ERROR: expect %d arguments, but %d are given\n", EXPECTED_ARGC, argc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int arg_i = 0; arg_i < argc; arg_i++) {
|
||||
const char* actual_arg = argv[arg_i];
|
||||
const char* expected_arg = expected_argv[arg_i];
|
||||
if (strcmp(actual_arg, expected_arg) != 0) {
|
||||
printf("ERROR: expect argument %d is %s, but given %s\n",
|
||||
arg_i, expected_arg, actual_arg);
|
||||
}
|
||||
}
|
||||
|
||||
printf("main()'s argc and argv are as expected\n");
|
||||
return 0;
|
||||
}
|
@ -2,3 +2,4 @@ include ../test_common.mk
|
||||
|
||||
EXTRA_C_FLAGS :=
|
||||
EXTRA_LINK_FLAGS :=
|
||||
BIN_ARGS :=
|
||||
|
@ -2,3 +2,4 @@ include ../test_common.mk
|
||||
|
||||
EXTRA_C_FLAGS :=
|
||||
EXTRA_LINK_FLAGS :=
|
||||
BIN_ARGS :=
|
||||
|
@ -2,3 +2,4 @@ include ../test_common.mk
|
||||
|
||||
EXTRA_C_FLAGS :=
|
||||
EXTRA_LINK_FLAGS :=
|
||||
BIN_ARGS :=
|
||||
|
@ -2,3 +2,4 @@ include ../test_common.mk
|
||||
|
||||
EXTRA_C_FLAGS :=
|
||||
EXTRA_LINK_FLAGS :=
|
||||
BIN_ARGS :=
|
||||
|
@ -2,3 +2,4 @@ include ../test_common.mk
|
||||
|
||||
EXTRA_C_FLAGS :=
|
||||
EXTRA_LINK_FLAGS :=
|
||||
BIN_ARGS :=
|
||||
|
@ -2,3 +2,4 @@ include ../test_common.mk
|
||||
|
||||
EXTRA_C_FLAGS :=
|
||||
EXTRA_LINK_FLAGS :=
|
||||
BIN_ARGS :=
|
||||
|
@ -2,3 +2,4 @@ include ../test_common.mk
|
||||
|
||||
EXTRA_C_FLAGS :=
|
||||
EXTRA_LINK_FLAGS :=
|
||||
BIN_ARGS :=
|
||||
|
@ -56,7 +56,7 @@ $(C_OBJS): %.o: %.c
|
||||
#############################################################################
|
||||
|
||||
test: $(BIN_ENC_NAME)
|
||||
@cd ../ && RUST_BACKTRACE=1 ./pal $(CUR_DIR)/$(BIN_ENC_NAME)
|
||||
@cd ../ && RUST_BACKTRACE=1 ./pal $(CUR_DIR)/$(BIN_ENC_NAME) $(BIN_ARGS)
|
||||
|
||||
#############################################################################
|
||||
# Misc
|
||||
|
@ -2,3 +2,4 @@ include ../test_common.mk
|
||||
|
||||
EXTRA_C_FLAGS :=
|
||||
EXTRA_LINK_FLAGS :=
|
||||
BIN_ARGS :=
|
||||
|
Loading…
Reference in New Issue
Block a user