Ejemplo n.º 1
0
// p = process.open(command) 
tb_int_t xm_process_open(lua_State* lua)
{
    // check
    tb_assert_and_check_return_val(lua, 0);

    // get the command
    size_t              command_size = 0;
    tb_char_t const*    command = luaL_checklstring(lua, 1, &command_size);
    tb_char_t const*    outfile = lua_tostring(lua, 2);
    tb_char_t const*    errfile = lua_tostring(lua, 3);
    tb_check_return_val(command, 0);

    // init attributes
    tb_process_attr_t attr = {0};

    // redirect stdout?
    if (outfile)
    {
        // redirect stdout to file
        attr.outfile = outfile;
        attr.outmode = TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_APPEND;

        // remove the outfile first
        if (tb_file_info(outfile, tb_null))
            tb_file_remove(outfile);
    }

    // redirect stderr?
    if (errfile)
    {
        // redirect stderr to file
        attr.errfile = errfile;
        attr.errmode = TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_APPEND;

        // remove the errfile first
        if (tb_file_info(errfile, tb_null))
            tb_file_remove(errfile);
    }

    // init process
    tb_process_ref_t process = tb_process_init_cmd(command, &attr);

    // save the process reference
    lua_pushlightuserdata(lua, process);

    // ok
    return 1;
}
Ejemplo n.º 2
0
tb_int_t xm_machine_main(xm_machine_ref_t machine, tb_int_t argc, tb_char_t** argv)
{
    // check
    xm_machine_impl_t* impl = (xm_machine_impl_t*)machine;
    tb_assert_and_check_return_val(impl && impl->lua, -1);

    // save main arguments to the global variable: _ARGV
    if (!xm_machine_main_save_arguments(impl, argc, argv)) return -1;

    // get the project directory
    tb_char_t path[TB_PATH_MAXN] = {0};
    if (!xm_machine_main_get_project_directory(impl, path, sizeof(path))) return -1;

    // get the program directory
    if (!xm_machine_main_get_program_directory(impl, path, sizeof(path))) return -1;

    // append the main script path
    tb_strcat(path, "/core/_xmake_main.lua");

    // exists this script?
    if (!tb_file_info(path, tb_null))
    {
        // error
        tb_printf("not found main script: %s\n", path);

        // failed
        return -1;
    }

    // trace
    tb_trace_d("main: %s", path);

    // load and execute the main script
    if (luaL_dofile(impl->lua, path))
    {
        // error
        tb_printf("error: %s\n", lua_tostring(impl->lua, -1));

        // failed
        return -1;
    }

    // set the error function
    lua_getglobal(impl->lua, "debug");
    lua_getfield(impl->lua, -1, "traceback");

    // call the main function
    lua_getglobal(impl->lua, "_xmake_main");
    if (lua_pcall(impl->lua, 0, 1, -2)) 
    {
        // error
        tb_printf("error: %s\n", lua_tostring(impl->lua, -1));

        // failed
        return -1;
    }

    // get the error code
    return (tb_int_t)lua_tonumber(impl->lua, -1);
}
Ejemplo n.º 3
0
tb_bool_t tb_directory_copy(tb_char_t const* path, tb_char_t const* dest)
{
    // the absolute path
    tb_char_t full0[TB_PATH_MAXN];
    path = tb_path_absolute(path, full0, TB_PATH_MAXN);
    tb_assert_and_check_return_val(path, tb_false);

    // the dest path
    tb_char_t full1[TB_PATH_MAXN];
    dest = tb_path_absolute(dest, full1, TB_PATH_MAXN);
    tb_assert_and_check_return_val(dest, tb_false);

    // walk copy
    tb_value_t tuple[3];
    tuple[0].cstr = dest;
    tuple[1].ul = tb_strlen(path);
    tuple[2].b = tb_true;
    tb_directory_walk(path, -1, tb_true, tb_directory_walk_copy, tuple);

    // ok?
    tb_bool_t ok = tuple[2].b;

    // copy empty directory?
    if (ok && !tb_file_info(dest, tb_null)) 
        return tb_directory_create(dest);

    // ok?
    return ok;
}
Ejemplo n.º 4
0
static tb_bool_t tb_directory_walk_impl(tb_char_t const* path, tb_bool_t recursion, tb_bool_t prefix, tb_directory_walk_func_t func, tb_cpointer_t priv)
{
    // check
    tb_assert_and_check_return_val(path && func, tb_false);

    // last
    tb_long_t       last = tb_strlen(path) - 1;
    tb_assert_and_check_return_val(last >= 0, tb_false);

    // done 
    tb_bool_t       ok = tb_true;
    tb_char_t       temp[4096] = {0};
    DIR*            directory = tb_null;
    if ((directory = opendir(path)))
    {
        // walk
        struct dirent* item = tb_null;
        while ((item = readdir(directory)))
        {
            // check
            tb_assert_and_check_continue(item->d_reclen);

            // the item name
            tb_char_t name[1024] = {0};
            tb_strncpy(name, item->d_name, tb_min(item->d_reclen, sizeof(name) - 1));
            if (tb_strcmp(name, ".") && tb_strcmp(name, ".."))
            {
                // the temp path
                tb_long_t n = tb_snprintf(temp, 4095, "%s%s%s", path, path[last] == '/'? "" : "/", name);
                if (n >= 0) temp[n] = '\0';

                // the file info
                tb_file_info_t info = {0};
                if (tb_file_info(temp, &info))
                {
                    // do callback
                    if (prefix) ok = func(temp, &info, priv);
                    tb_check_break(ok);

                    // walk to the next directory
                    if (info.type == TB_FILE_TYPE_DIRECTORY && recursion) ok = tb_directory_walk_impl(temp, recursion, prefix, func, priv);
                    tb_check_break(ok);
    
                    // do callback
                    if (!prefix) ok = func(temp, &info, priv);
                    tb_check_break(ok);
                }
            }
        }

        // exit directory
        closedir(directory);
    }

    // continue ?
    return ok;
}
Ejemplo n.º 5
0
/* //////////////////////////////////////////////////////////////////////////////////////
 * interfaces
 */
tb_bool_t tb_dns_init()
{
    // done
    tb_size_t count = 0;
    if (tb_file_info("/etc/resolv.conf", tb_null)) 
    {
        /* try get list from "/etc/resolv.conf"
         *
         * # Generated by NetworkManager
         * nameserver 10.1.20.10
         * nameserver 8.8.8.8
         *
         */
        tb_stream_ref_t stream = tb_stream_init_from_url("/etc/resolv.conf");
        if (stream)
        {
            // open
            if (tb_stream_open(stream)) 
            {
                // read
                tb_long_t size = 0;
                tb_char_t line[8192];
                while ((size = tb_stream_bread_line(stream, line, 8192)) >= 0)
                {
                    if (size && !tb_strnicmp(line, "nameserver", 10))
                    {
                        // seek to server
                        tb_char_t const* p = line + 10;
                        while (*p && !tb_isdigit(*p)) p++;
                        tb_check_continue(*p);

                        // add server
                        tb_dns_server_add(p);

                        // count++
                        count++;
                    }
                }
            }
    
            // exit
            tb_stream_exit(stream);
        }
    }

    // no server? add the default server
    if (!count) 
    {
        tb_dns_server_add("8.8.8.8");
        tb_dns_server_add("8.8.8.4");
    }

    // ok
    return tb_true;
}
Ejemplo n.º 6
0
static tb_void_t tb_directory_walk_impl(tb_wchar_t const* path, tb_bool_t recursion, tb_bool_t prefix, tb_directory_walk_func_t func, tb_cpointer_t priv)
{
    // check
    tb_assert_and_check_return(path && func);

    // last
    tb_long_t           last = tb_wcslen(path) - 1;
    tb_assert_and_check_return(last >= 0);

    // add \*.*
    tb_wchar_t          temp_w[4096] = {0};
    tb_char_t           temp_a[4096] = {0};
    tb_swprintf(temp_w, 4095, L"%s%s*.*", path, path[last] == L'\\'? L"" : L"\\");

    // init info
    WIN32_FIND_DATAW    find = {0};
    HANDLE              directory = INVALID_HANDLE_VALUE;
    if (INVALID_HANDLE_VALUE != (directory = FindFirstFileW(temp_w, &find)))
    {
        // walk
        do
        {
            // check
            if (tb_wcscmp(find.cFileName, L".") && tb_wcscmp(find.cFileName, L".."))
            {
                // the temp path
                tb_long_t n = tb_swprintf(temp_w, 4095, L"%s%s%s", path, path[last] == L'\\'? L"" : L"\\", find.cFileName);
                if (n >= 0 && n < 4096) temp_w[n] = L'\0';

                // wtoa temp
                n = tb_wtoa(temp_a, temp_w, 4095);
                if (n >= 0 && n < 4096) temp_a[n] = '\0';

                // the file info
                tb_file_info_t info = {0};
                if (tb_file_info(temp_a, &info))
                {
                    // do callback
                    if (prefix) func(temp_a, &info, priv);

                    // walk to the next directory
                    if (info.type == TB_FILE_TYPE_DIRECTORY && recursion) tb_directory_walk_impl(temp_w, recursion, prefix, func, priv);
    
                    // do callback
                    if (!prefix) func(temp_a, &info, priv);
                }
            }

        } while (FindNextFileW(directory, &find));

        // exit directory
        FindClose(directory);
    }
}
Ejemplo n.º 7
0
/* //////////////////////////////////////////////////////////////////////////////////////
 * implementation
 */
tb_int_t xm_os_exists(lua_State* lua)
{
    // check
    tb_assert_and_check_return_val(lua, 0);

    // get the path 
    tb_char_t const* path = luaL_checkstring(lua, 1);
    tb_check_return_val(path, 0);

    // done os.exists(path) 
    lua_pushboolean(lua, tb_file_info(path, tb_null));

    // ok
    return 1;
}
Ejemplo n.º 8
0
/* //////////////////////////////////////////////////////////////////////////////////////
 * main
 */ 
tb_int_t tb_demo_coroutine_http_server_main(tb_int_t argc, tb_char_t** argv)
{
    // done
    tb_socket_ref_t sock = tb_null;
    do
    {
        // init socket
        sock = tb_socket_init(TB_SOCKET_TYPE_TCP, TB_IPADDR_FAMILY_IPV4);
        tb_assert_and_check_break(sock);

        // bind socket
        tb_ipaddr_t addr;
        tb_ipaddr_set(&addr, tb_null, TB_DEMO_PORT, TB_IPADDR_FAMILY_IPV4);
        if (!tb_socket_bind(sock, &addr)) break;

        // listen socket
        if (!tb_socket_listen(sock, 1000)) break;

        // init the root directory
        if (argv[1]) tb_strlcpy(g_rootdir, argv[1], sizeof(g_rootdir));
        else tb_directory_current(g_rootdir, sizeof(g_rootdir));

        // only data?
        if (!tb_file_info(g_rootdir, tb_null)) g_onlydata = tb_true;

        // trace
        tb_trace_i("%s: %s", g_onlydata? "data" : "rootdir", g_rootdir);

#if TB_DEMO_CPU > 1
        // start workers for multi-threads
        tb_size_t count = TB_DEMO_CPU - 1;
        while (count--) tb_thread_init(tb_null, tb_demo_coroutine_worker, sock, 0);
#endif

        // start worker
        tb_demo_coroutine_worker(sock);

    } while (0);

    // exit socket
    if (sock) tb_socket_exit(sock);
    sock = tb_null;

    // ok
    return 0;
}
Ejemplo n.º 9
0
Archivo: mkdir.c Proyecto: waruqi/xmake
/* //////////////////////////////////////////////////////////////////////////////////////
 * implementation
 */
tb_int_t xm_os_mkdir(lua_State* lua)
{
    // check
    tb_assert_and_check_return_val(lua, 0);

    // get the path 
    tb_char_t const* path = luaL_checkstring(lua, 1);
    tb_check_return_val(path, 0);

    // os.mkdir(path) 
    tb_file_info_t info = {0};
    if (!tb_file_info(path, &info) || (info.type != TB_FILE_TYPE_DIRECTORY))
        lua_pushboolean(lua, tb_directory_create(path));
    else lua_pushboolean(lua, tb_true);

    // ok
    return 1;
}
Ejemplo n.º 10
0
Archivo: mtime.c Proyecto: waruqi/xmake
/* //////////////////////////////////////////////////////////////////////////////////////
 * implementation
 */
tb_int_t xm_os_mtime(lua_State* lua)
{
    // check
    tb_assert_and_check_return_val(lua, 0);

    // get the path 
    tb_char_t const* path = luaL_checkstring(lua, 1);
    tb_check_return_val(path, 0);

    // done os.mtime(path) 
    tb_file_info_t info = {0};
    if (tb_file_info(path, &info) && (info.type == TB_FILE_TYPE_FILE))
        lua_pushinteger(lua, (lua_Integer)info.mtime);
    else lua_pushinteger(lua, 0);

    // ok
    return 1;
}
Ejemplo n.º 11
0
static tb_bool_t tb_directory_walk_copy(tb_char_t const* path, tb_file_info_t const* info, tb_cpointer_t priv)
{
    // check
    tb_value_t* tuple = (tb_value_t*)priv;
    tb_assert_and_check_return_val(path && info && tuple, tb_false);

    // the dest directory
    tb_char_t const* dest = tuple[0].cstr;
    tb_assert_and_check_return_val(dest, tb_false);

    // the file name
    tb_size_t size = tuple[1].ul;
    tb_char_t const* name = path + size;

    // the dest file path
    tb_char_t dpath[8192] = {0};
    tb_snprintf(dpath, 8192, "%s\\%s", dest, name[0] == '\\'? name + 1 : name);

    // remove the dest file first
    tb_file_info_t dinfo = {0};
    if (tb_file_info(dpath, &dinfo))
    {
        if (dinfo.type == TB_FILE_TYPE_FILE)
            tb_file_remove(dpath);
        if (dinfo.type == TB_FILE_TYPE_DIRECTORY)
            tb_directory_remove(dpath);
    }

    // copy 
    switch (info->type)
    {
    case TB_FILE_TYPE_FILE:
        if (!tb_file_copy(path, dpath)) tuple[2].b = tb_false;
        break;
    case TB_FILE_TYPE_DIRECTORY:
        if (!tb_directory_create(dpath)) tuple[2].b = tb_false;
        break;
    default:
        break;
    }

    // continue
    return tb_true;
}
Ejemplo n.º 12
0
tb_void_t tb_directory_walk(tb_char_t const* path, tb_bool_t recursion, tb_bool_t prefix, tb_directory_walk_func_t func, tb_cpointer_t priv)
{
    // check
    tb_assert_and_check_return(path && func);

    // exists?
    tb_file_info_t info = {0};
    if (tb_file_info(path, &info) && info.type == TB_FILE_TYPE_DIRECTORY) 
        tb_directory_walk_impl(path, recursion, prefix, func, priv);
    else
    {
        // the absolute path
        tb_char_t full[TB_PATH_MAXN];
        path = tb_path_absolute(path, full, TB_PATH_MAXN);
        tb_assert_and_check_return(path);

        // walk
        tb_directory_walk_impl(path, recursion, prefix, func, priv);
    }
}
Ejemplo n.º 13
0
tb_void_t tb_directory_walk(tb_char_t const* path, tb_long_t recursion, tb_bool_t prefix, tb_directory_walk_func_t func, tb_cpointer_t priv)
{
    // check
    tb_assert_and_check_return(path && func);

    // walk it directly if rootdir is relative path
    tb_file_info_t info = {0};
    if (!tb_path_is_absolute(path) && tb_file_info(path, &info) && info.type == TB_FILE_TYPE_DIRECTORY) 
    {
        tb_wchar_t path_w[TB_PATH_MAXN];
        if (tb_atow(path_w, path, tb_arrayn(path_w)) != -1)
            tb_directory_walk_impl(path_w, recursion, prefix, func, priv);
    }
    else
    {
        // the absolute path (translate "~/")
        tb_wchar_t full_w[TB_PATH_MAXN];
        if (tb_path_absolute_w(path, full_w, TB_PATH_MAXN))
            tb_directory_walk_impl(full_w, recursion, prefix, func, priv);
    }
}
Ejemplo n.º 14
0
/* //////////////////////////////////////////////////////////////////////////////////////
 * implementation
 */
tb_bool_t tb_directory_create(tb_char_t const* path)
{
    // check
    tb_assert_and_check_return_val(path, tb_false);

    // the absolute path
    tb_char_t full[TB_PATH_MAXN];
    path = tb_path_absolute(path, full, TB_PATH_MAXN);
    tb_assert_and_check_return_val(path, tb_false);

    // make it
    tb_bool_t ok = !mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO)? tb_true : tb_false;
    if (!ok)
    {
        // make directory
        tb_char_t           temp[TB_PATH_MAXN] = {0};
        tb_char_t const*    p = full;
        tb_char_t*          t = temp;
        tb_char_t const*    e = temp + TB_PATH_MAXN - 1;
        for (; t < e && *p; t++) 
        {
            *t = *p;
            if (*p == '/')
            {
                // make directory if not exists
                if (!tb_file_info(temp, tb_null)) mkdir(temp, S_IRWXU | S_IRWXG | S_IRWXO);

                // skip repeat '/'
                while (*p && *p == '/') p++;
            }
            else p++;
        }

        // make it again
        ok = !mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO)? tb_true : tb_false;
    }

    // ok?
    return ok;
}
Ejemplo n.º 15
0
static tb_bool_t tb_demo_spider_task_done(tb_demo_spider_t* spider, tb_char_t const* iurl, tb_bool_t* full)
{
    // check
    tb_assert_and_check_return_val(spider && iurl, tb_false);

    // killed?
    tb_check_return_val(TB_STATE_OK == tb_atomic_get(&spider->state), tb_false);

    // only for home?
    if (spider->home_only && !tb_stristr(iurl, spider->home_domain)) 
    {
        // trace
        tb_trace_d("task: done: %s: skip", iurl);
        return tb_true;
    }

    // enter
    tb_spinlock_enter(&spider->lock);

    // done
    tb_bool_t               ok = tb_false;
    tb_size_t               size = 0;
    tb_demo_spider_task_t*  task = tb_null;
    tb_bool_t               repeat = tb_false;
    do
    {
        // check
        tb_assert_and_check_break(spider->filter && spider->pool);

        // the task count
        size = tb_fixed_pool_size(spider->pool);
        
        // make the output url
        if (!tb_demo_spider_make_ourl(spider, iurl, spider->ourl, sizeof(spider->ourl) - 1)) break;

        // have been done already?
        if (!tb_bloom_filter_set(spider->filter, spider->ourl)) 
        {
            // trace
            tb_trace_d("task: size: %lu, done: %s: repeat", size, iurl);

            // ok
            ok = tb_true;
            repeat = tb_true;
            break;
        }

        // trace
        tb_trace_d("task: size: %lu, done: %s: ..", size, iurl);

        // full?
        tb_check_break(size < TB_DEMO_SPIDER_TASK_MAXN);

        // make task
        task = (tb_demo_spider_task_t*)tb_fixed_pool_malloc0(spider->pool);
        tb_assert_and_check_break(task);

        // init task
        task->spider = spider;
        tb_strlcpy(task->iurl, iurl, sizeof(task->iurl) - 1);
        tb_strlcpy(task->ourl, spider->ourl, sizeof(task->ourl) - 1);
           
        // ok 
        ok = tb_true;

    } while (0);

    // leave
    tb_spinlock_leave(&spider->lock);

    // ok?
    if (ok && !repeat)
    {
        // done
        ok = tb_false;
        do
        {
            // check
            tb_assert_and_check_break(task);

            // killed?
            tb_check_break(TB_STATE_OK == tb_atomic_get(&spider->state));

            // repeat?
            if (tb_file_info(task->ourl, tb_null))
            {
                // trace
                tb_trace_d("task: size: %lu, done: %s: repeat", size, iurl);

                // ok
                ok = tb_true;
                repeat = tb_true;
                break;
            }

            // done task
            ok = tb_transfer_pool_done(tb_transfer_pool(), task->iurl, task->ourl, 0, spider->limited_rate, tb_demo_spider_task_save, tb_demo_spider_task_ctrl, task);
            tb_assert_and_check_break(ok);

        } while (0);
    }

    // repeat or failed?
    if (repeat || !ok)
    {
        // exit task
        if (task) tb_demo_spider_task_exit(task);
        task = tb_null;

        // failed?
        if (!full && !ok)
        {
            // trace
            tb_trace_e("task: size: %lu, done: %s: post failed", size, iurl);
        }

        // save full
        if (full) *full = size < TB_DEMO_SPIDER_TASK_MAXN? tb_false : tb_true;
    }

    // ok?
    return ok;
}
Ejemplo n.º 16
0
static tb_bool_t it_inject(pid_t pid, tb_char_t const* path) 
{
    // check
    tb_assert_and_check_return_val(pid && path, tb_false);

    // trace
    tb_trace_d("inject: pid: %lu, path: %s: ..", (tb_size_t)pid, path);

#ifdef TB_ARCH_ARM64
    // uses libsubstrate first?
    if (tb_file_info("/usr/lib/libsubstrate.dylib", tb_null))
    {
        // init library
        tb_bool_t   ok = tb_false;
        tb_handle_t library = tb_dynamic_init("/usr/lib/libsubstrate.dylib");
        if (library)
        {
            // trace
            tb_trace_d("library: %p", library);

            // the func
            it_MSHookProcess_t pMSHookProcess = tb_dynamic_func(library, "MSHookProcess");
            if (pMSHookProcess)
            {
                // trace
                tb_trace_d("MSHookProcess: %p", pMSHookProcess);

                // hook process
                ok = pMSHookProcess(pid, path)? tb_true : tb_false;
            }

            // exit library
            tb_dynamic_exit(library);

            // trace
            tb_trace_i("%s", ok? "ok" : "no");

            // ok?
            return ok;
        }
    }
#endif

    // pid => task
    task_t task = 0;
    if (task_for_pid(mach_task_self(), (tb_int_t)pid, &task)) 
    {
        tb_trace_i("task_for_pid: %lu failed, errno: %d", (tb_size_t)pid, errno);
        return tb_false;
    }

    // trace
    tb_trace_d("task: %u", task);

    // stuff
    cpu_type_t cputype; it_addr_bundle_t addrs;
    if (!it_stuff(task, &cputype, &addrs)) return tb_false;

    // trace
    tb_trace_d("dlopen: %p", addrs.dlopen);
    tb_trace_d("syscall: %p", addrs.syscall);

    // alloc stack 
    mach_vm_address_t stack_address = 0;
    if (mach_vm_allocate(task, &stack_address, it_stack_size, VM_FLAGS_ANYWHERE)) return tb_false;

    // write path
    mach_vm_address_t stack_end = stack_address + it_stack_size - 0x100;
    if (mach_vm_write(task, stack_address, (vm_offset_t)it_address_cast(path), strlen(path) + 1)) return tb_false;

    /* the first one is the return address
     *
     * syscall(SYS_bsdthread_create, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0)
     */
    tb_uint32_t args_32[] = {0, 360, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0};
    tb_uint64_t args_64[] = {0, 360, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0};

    // init thread state 
    union
    {
        it_arm_thread_state_t       arm;
        it_arm_thread_state64_t     arm64;
        it_x86_thread_state32_t     x86;
        it_x86_thread_state64_t     x64;
        natural_t                   nat;

    }state;
    thread_state_flavor_t           state_flavor;
    mach_msg_type_number_t          state_count;
    memset(&state, 0, sizeof(state));   

    // init thread state for the cpu type
    switch (cputype)
    {
    case CPU_TYPE_ARM:
        {
            tb_trace_i("cputype: arm");
            memcpy(&state.arm.r[0], args_32 + 1, 4 * sizeof(tb_uint32_t));
            if (mach_vm_write(task, stack_end, (vm_offset_t)it_address_cast(args_32 + 5), 2 * sizeof(tb_uint32_t))) return tb_false;

            state.arm.sp    = (tb_uint32_t) stack_end;
            state.arm.pc    = (tb_uint32_t) addrs.syscall;
            state.arm.lr    = (tb_uint32_t) args_32[0];

            state_flavor    = ARM_THREAD_STATE;
            state_count     = sizeof(state.arm) / sizeof(state.nat);

            // trace
            tb_trace_d("init: pc: %x", state.arm.pc);
            tb_trace_d("init: lr: %x", state.arm.lr);
            tb_trace_d("init: sp: %x", state.arm.sp);
        }
        break;
    case CPU_TYPE_ARM64:
        {
            tb_trace_i("cputype: arm64");
            memcpy(&state.arm64.x[0], args_64 + 1, 6 * sizeof(tb_uint64_t));

            state.arm64.sp  = (tb_uint64_t) stack_end;
//          state.arm64.fp  = (tb_uint64_t) stack_end;
            state.arm64.pc  = (tb_uint64_t) addrs.syscall;
            state.arm64.lr  = (tb_uint64_t) args_64[0];

            state_flavor    = ARM_THREAD_STATE64;
            state_count     = sizeof(state.arm64) / sizeof(state.nat);

            // trace
            tb_trace_d("init: pc: %llx", state.arm64.pc);
            tb_trace_d("init: lr: %llx", state.arm64.lr);
            tb_trace_d("init: sp: %llx", state.arm64.sp);
        }
        break;
    case CPU_TYPE_X86:
        {
            tb_trace_i("cputype: x86");
            if (mach_vm_write(task, stack_end, (vm_offset_t)it_address_cast(args_32), 7 * 4)) return tb_false;

            state.x86.esp   = state.x86.ebp = (tb_uint32_t) stack_end;
            state.x86.eip   = (tb_uint32_t)addrs.syscall;

            state_flavor    = x86_THREAD_STATE32;
            state_count     = sizeof(state.x86) / sizeof(state.nat);
        }
        break;
    case CPU_TYPE_X86_64:
        {
            tb_trace_i("cputype: x64");
            state.x64.rdi   = args_64[1];
            state.x64.rsi   = args_64[2];
            state.x64.rdx   = args_64[3];
            state.x64.rcx   = args_64[4];
            state.x64.r8    = args_64[5];
            state.x64.r9    = args_64[6];

            state.x64.rsp   = state.x64.rbp = stack_end;
            state.x64.rip   = addrs.syscall;

            state_flavor    = x86_THREAD_STATE64;
            state_count     = sizeof(state.x64) / sizeof(state.nat);
        }
        break;
    default:
        tb_trace_i("cputype: unknown: %lx", (tb_size_t)cputype);
        return tb_false;
    }

    // init a remote thread
    thread_act_t thread = 0;
    if (thread_create(task, &thread)) return tb_false;

    // trace
    tb_trace_d("init: thread: %x", thread);

    // alloc port
    mach_port_t exc = 0;
    mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exc);
    if (mach_port_insert_right(mach_task_self(), exc, exc, MACH_MSG_TYPE_MAKE_SEND)) return tb_false;

    // swap port
    exception_mask_t        em[2];
    exception_handler_t     eh[2];
    exception_behavior_t    eb[2];
    thread_state_flavor_t   ef[2];
    mach_msg_type_number_t  em_count = 2;
    if (task_swap_exception_ports(task, EXC_MASK_BAD_ACCESS, exc, EXCEPTION_STATE_IDENTITY, state_flavor, em, &em_count, eh, eb, ef)) return tb_false;
    tb_assert_and_check_return_val(em_count <= 1, tb_false);

    // resume thread, done: syscall(SYS_bsdthread_create, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0)
    if (thread_set_state(thread, state_flavor, &state.nat, state_count)) return tb_false;
    if (thread_resume(thread)) return tb_false;

    // we expect three exceptions: one from thread when it returns, one from the new thread when it calls the fake handler, and one from the new thread when it returns from dlopen.
    tb_bool_t started_dlopen = tb_false;
    while (1) 
    {
        // recv msg
        it_exception_message_t msg;
        if (mach_msg_overwrite(tb_null, MACH_RCV_MSG, 0, sizeof(msg), exc, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, (tb_pointer_t) &msg, sizeof(msg))) return tb_false;

        // trace
        tb_trace_d("recv: msg: from thread: %x", msg.thread.name);

        // check
        tb_assert_and_check_return_val((msg.Head.msgh_bits & MACH_MSGH_BITS_COMPLEX), tb_false);
        tb_assert_and_check_return_val((msg.msgh_body.msgh_descriptor_count != 0), tb_false);
        tb_assert_and_check_return_val((msg.Head.msgh_size >= offsetof(it_exception_message_t, old_state)), tb_false);
        tb_assert_and_check_return_val((msg.old_stateCnt == state_count), tb_false);
        tb_assert_and_check_return_val((msg.Head.msgh_size >= offsetof(it_exception_message_t, old_state) + msg.old_stateCnt * sizeof(natural_t)), tb_false);

        // the msg state
        memcpy(&state, msg.old_state, sizeof(state));

        // dump
//      tb_dump_data((tb_byte_t const*)&state, sizeof(state));

        // done
        if (msg.thread.name == thread)
        {
            tb_trace_d("terminate");
            if (thread_terminate(thread)) return tb_false;
        } 
        else
        {
            // init cond
            tb_bool_t cond = tb_false;
            switch(cputype)
            {
            case CPU_TYPE_ARM:      
                {
                    // trace
                    tb_trace_d("recv: pc: %x", state.arm.pc);
                    tb_trace_d("recv: lr: %x", state.arm.lr);
                    tb_trace_d("recv: sp: %x", state.arm.sp);

                    // cond
                    cond = ((state.arm.pc & ~1) == 0xdeadbeee)? tb_true : tb_false;
                }
                break;
            case CPU_TYPE_ARM64:
                {
                    // trace
                    tb_trace_d("recv: pc: %llx", state.arm64.pc);
                    tb_trace_d("recv: lr: %llx", state.arm64.lr);
                    tb_trace_d("recv: sp: %llx", state.arm64.sp);

                    // cond
                    cond = ((state.arm64.pc & ~1) == 0xdeadbeee)? tb_true : tb_false;
                }
                break;
            case CPU_TYPE_X86:
                cond = (state.x86.eip == 0xdeadbeef)? tb_true : tb_false; 
                break;
            case CPU_TYPE_X86_64:
                cond = (state.x64.rip == 0xdeadbeef)? tb_true : tb_false;
                break;
            }

            tb_trace_d("cond: %d, started_dlopen: %d", cond, started_dlopen);
            if (!cond)
            {
                // let the normal crash mechanism handle it
                task_set_exception_ports(task, em[0], eh[0], eb[0], ef[0]);
                tb_assert_and_check_return_val(0, tb_false);
            }
            else if (started_dlopen)
            {
                tb_trace_d("terminate");
                if (thread_terminate(msg.thread.name)) return tb_false;
                break;
            }
            else 
            {
                // done: dlopen(path, RTLD_LAZY)
                switch(cputype)
                {
                case CPU_TYPE_ARM:
                    {
                        state.arm.r[0] = (tb_uint32_t) stack_address;
                        state.arm.r[1] = RTLD_LAZY;
                        state.arm.pc = (tb_uint32_t) addrs.dlopen;
                        state.arm.lr = 0xdeadbeef;
                    }
                    break;
                case CPU_TYPE_ARM64:
                    {
                        state.arm64.x[0] = (tb_uint64_t) stack_address;
                        state.arm64.x[1] = RTLD_LAZY;
                        state.arm64.pc = (tb_uint64_t) addrs.dlopen;
                        state.arm64.lr = 0xdeadbeef;
                    }
                    break;
                case CPU_TYPE_X86:
                    {
                        tb_uint32_t stack_stuff[3] = {0xdeadbeef, (tb_uint32_t)stack_address, RTLD_LAZY};
                        if (mach_vm_write(task, (mach_vm_address_t)state.x86.esp, (vm_offset_t)it_address_cast(&stack_stuff), sizeof(stack_stuff))) return tb_false;
                    }
                    state.x86.eip = (tb_uint32_t) addrs.dlopen;
                    break;
                case CPU_TYPE_X86_64:
                    {
                        tb_uint64_t stack_stuff = 0xdeadbeef;
                        if (mach_vm_write(task, (mach_vm_address_t)state.x64.rsp, (vm_offset_t)it_address_cast(&stack_stuff), sizeof(stack_stuff))) return tb_false;
                        state.x64.rip = addrs.dlopen;
                        state.x64.rdi = stack_address;
                        state.x64.rsi = RTLD_LAZY;
                    }
                    break;
                }

                it_exception_reply_t reply;
                memcpy(&reply.Head, &msg.Head, sizeof(mach_msg_header_t));
                reply.Head.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
                reply.Head.msgh_size = offsetof(it_exception_reply_t, new_state) + state_count * sizeof(natural_t);
                reply.Head.msgh_id += 100;
                memcpy(&reply.NDR, &msg.NDR, sizeof(NDR_record_t));
                reply.RetCode = 0;
                reply.flavor = state_flavor;
                reply.new_stateCnt = state_count;
                memcpy(&reply.new_state, &state, sizeof(state));

                if (thread_set_state(msg.thread.name, state_flavor, &state.nat, state_count)) return tb_false;
                if (mach_msg(&reply.Head, MACH_SEND_MSG, reply.Head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)) return tb_false;
                started_dlopen = tb_true;
            }
        }
    }

    // exit
    if (stack_address) vm_deallocate(task, stack_address, it_stack_size);
    if (thread)
    {
        thread_terminate(thread);
        mach_port_deallocate(mach_task_self(), thread);
    }
    if (task) mach_port_deallocate(mach_task_self(), task);
    if (exc) mach_port_deallocate(mach_task_self(), exc);

    // ok
    tb_trace_i("ok");
    return tb_true;
}
Ejemplo n.º 17
0
// p = process.openv(shellname, argv, outfile, errfile) 
tb_int_t xm_process_openv(lua_State* lua)
{
    // check
    tb_assert_and_check_return_val(lua, 0);

    // check table
    if (!lua_istable(lua, 2))
    {
        // error
        lua_pushfstring(lua, "invalid argv type(%s) for process.openv", luaL_typename(lua, 2));
        lua_error(lua);
        return 0;
    }

    // get the output and error file
    tb_char_t const* shellname  = lua_tostring(lua, 1);
    tb_char_t const* outfile    = lua_tostring(lua, 3);
    tb_char_t const* errfile    = lua_tostring(lua, 4);
    tb_check_return_val(shellname, 0);

    // get the arguments count
    tb_long_t argn = lua_objlen(lua, 2);
    tb_check_return_val(argn >= 0, 0);
    
    // get arguments
    tb_size_t           argi = 0;
    tb_char_t const**   argv = tb_nalloc0_type(1 + argn + 1, tb_char_t const*);
    tb_check_return_val(argv, 0);

    // fill arguments
    argv[0] = shellname;
    for (argi = 0; argi < argn; argi++)
    {
        // get argv[i]
        lua_pushinteger(lua, argi + 1);
        lua_gettable(lua, 2);

        // is string?
        if (lua_isstring(lua, -1))
        {
            // pass this argument
            argv[1 + argi] = lua_tostring(lua, -1);
        }
        else
        {
            // error
            lua_pushfstring(lua, "invalid argv[%ld] type(%s) for process.openv", argi, luaL_typename(lua, -1));
            lua_error(lua);
        }

        // pop it
        lua_pop(lua, 1);
    }

    // init attributes
    tb_process_attr_t attr = {0};

    // redirect stdout?
    if (outfile)
    {
        // redirect stdout to file
        attr.outfile = outfile;
        attr.outmode = TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_APPEND;

        // remove the outfile first
        if (tb_file_info(outfile, tb_null))
            tb_file_remove(outfile);
    }

    // redirect stderr?
    if (errfile)
    {
        // redirect stderr to file
        attr.errfile = errfile;
        attr.errmode = TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_APPEND;

        // remove the errfile first
        if (tb_file_info(errfile, tb_null))
            tb_file_remove(errfile);
    }

    // init process
    tb_process_ref_t process = tb_process_init(shellname, argv, &attr);
    if (process) lua_pushlightuserdata(lua, process);
    else lua_pushnil(lua);

    // exit argv
    if (argv) tb_free(argv);
    argv = tb_null;

    // ok
    return 1;
}