/** * Execute selected states of the bootm command. * * Note the arguments to this state must be the first argument, Any 'bootm' * or sub-command arguments must have already been taken. * * Note that if states contains more than one flag it MUST contain * BOOTM_STATE_START, since this handles and consumes the command line args. * * Also note that aside from boot_os_fn functions and bootm_load_os no other * functions we store the return value of in 'ret' may use a negative return * value, without special handling. * * @param cmdtp Pointer to bootm command table entry * @param flag Command flags (CMD_FLAG_...) * @param argc Number of subcommand arguments (0 = no arguments) * @param argv Arguments * @param states Mask containing states to run (BOOTM_STATE_...) * @param images Image header information * @param boot_progress 1 to show boot progress, 0 to not do this * @return 0 if ok, something else on error. Some errors will cause this * function to perform a reboot! If states contains BOOTM_STATE_OS_GO * then the intent is to boot an OS, so this function will not return * unless the image type is standalone. */ static int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], int states, bootm_headers_t *images, int boot_progress) { boot_os_fn *boot_fn; ulong iflag = 0; int ret = 0; images->state |= states; /* * Work through the states and see how far we get. We stop on * any error. */ if (states & BOOTM_STATE_START) ret = bootm_start(cmdtp, flag, argc, argv); if (!ret && (states & BOOTM_STATE_FINDOS)) ret = bootm_find_os(cmdtp, flag, argc, argv); if (!ret && (states & BOOTM_STATE_FINDOTHER)) { ret = bootm_find_other(cmdtp, flag, argc, argv); argc = 0; /* consume the args */ } /* * We have reached the point of no return: we are going to * overwrite all exception vector code, so we cannot easily * recover from any failures any more... */ iflag = disable_interrupts(); #ifdef CONFIG_NETCONSOLE /* Stop the ethernet stack if NetConsole could have left it up */ eth_halt(); #endif #if defined(CONFIG_CMD_USB) /* * turn off USB to prevent the host controller from writing to the * SDRAM while Linux is booting. This could happen (at least for OHCI * controller), because the HCCA (Host Controller Communication Area) * lies within the SDRAM and the host controller writes continously to * this area (as busmaster!). The HccaFrameNumber is for example * updated every 1 ms within the HCCA structure in SDRAM! For more * details see the OpenHCI specification. */ usb_stop(); #endif /* Load the OS */ if (!ret && (states & BOOTM_STATE_LOADOS)) { ulong load_end; ret = bootm_load_os(images, &load_end, 0); if (ret && ret != BOOTM_ERR_OVERLAP) goto err; if (ret == 0) lmb_reserve(&images->lmb, images->os.load, (load_end - images->os.load)); else if (ret == BOOTM_ERR_OVERLAP) ret = 0; } /* Relocate the ramdisk */ #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH if (!ret && (states & BOOTM_STATE_RAMDISK)) { ulong rd_len = images->rd_end - images->rd_start; ret = boot_ramdisk_high(&images->lmb, images->rd_start, rd_len, &images->initrd_start, &images->initrd_end); if (!ret) { setenv_hex("initrd_start", images->initrd_start); setenv_hex("initrd_end", images->initrd_end); } } #endif #if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB) if (!ret && (states & BOOTM_STATE_FDT)) { boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr); ret = boot_relocate_fdt(&images->lmb, &images->ft_addr, &images->ft_len); } #endif /* From now on, we need the OS boot function */ if (ret) return ret; boot_fn = boot_os[images->os.os]; if (boot_fn == NULL) { if (iflag) enable_interrupts(); printf("ERROR: booting os '%s' (%d) is not supported\n", genimg_get_os_name(images->os.os), images->os.os); bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); return 1; } /* Call various other states that are not generally used */ if (!ret && (states & BOOTM_STATE_OS_CMDLINE)) ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images); if (!ret && (states & BOOTM_STATE_OS_BD_T)) ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images); if (!ret && (states & BOOTM_STATE_OS_PREP)) ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images); #ifdef CONFIG_TRACE /* Pretend to run the OS, then run a user command */ if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) { char *cmd_list = getenv("fakegocmd"); ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO, images, boot_fn); if (!ret && cmd_list) ret = run_command_list(cmd_list, -1, flag); } #endif /* Now run the OS! We hope this doesn't return */ if (!ret && (states & BOOTM_STATE_OS_GO)) { ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO, images, boot_fn); if (ret) goto err; } return ret; /* Deal with any fallout */ err: if (iflag) enable_interrupts(); if (ret == BOOTM_ERR_UNIMPLEMENTED) bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); else if (ret == BOOTM_ERR_RESET) do_reset(cmdtp, flag, argc, argv); else puts("subcommand not supported\n"); return ret; }
int main(int argc, char **argv) { int res = 1; int my_optind = 0; program_name = L"fish"; set_main_thread(); setup_fork_guards(); signal_unblock_all(); setlocale(LC_ALL, ""); fish_setlocale(); // struct stat tmp; // stat("----------FISH_HIT_MAIN----------", &tmp); const char *dummy_argv[2] = {"fish", NULL}; if (!argv[0]) { argv = (char **)dummy_argv; //!OCLINT(parameter reassignment) argc = 1; //!OCLINT(parameter reassignment) } fish_cmd_opts_t opts; my_optind = fish_parse_opt(argc, argv, &opts); // No-exec is prohibited when in interactive mode. if (is_interactive_session && no_exec) { debug(1, _(L"Can not use the no-execute mode when running an interactive session")); no_exec = 0; } // Only save (and therefore restore) the fg process group if we are interactive. See issues // #197 and #1002. if (is_interactive_session) { save_term_foreground_process_group(); } auto &globals = env_stack_t::globals(); const struct config_paths_t paths = determine_config_directory_paths(argv[0]); env_init(&paths); // Set features early in case other initialization depends on them. // Start with the ones set in the environment, then those set on the command line (so the // command line takes precedence). if (auto features_var = globals.get(L"fish_features")) { for (const wcstring &s : features_var->as_list()) { mutable_fish_features().set_from_string(s); } } mutable_fish_features().set_from_string(opts.features); proc_init(); builtin_init(); misc_init(); reader_init(); parser_t &parser = parser_t::principal_parser(); if (read_init(paths)) { // Stomp the exit status of any initialization commands (issue #635). proc_set_last_status(STATUS_CMD_OK); // Run post-config commands specified as arguments, if any. if (!opts.postconfig_cmds.empty()) { res = run_command_list(&opts.postconfig_cmds, {}); } if (!opts.batch_cmds.empty()) { // Run the commands specified as arguments, if any. if (is_login) { // Do something nasty to support OpenSUSE assuming we're bash. This may modify cmds. fish_xdm_login_hack_hack_hack_hack(&opts.batch_cmds, argc - my_optind, argv + my_optind); } res = run_command_list(&opts.batch_cmds, {}); reader_set_end_loop(false); } else if (my_optind == argc) { // Implicitly interactive mode. res = reader_read(STDIN_FILENO, {}); } else { char *file = *(argv + (my_optind++)); int fd = open(file, O_RDONLY); if (fd == -1) { perror(file); } else { // OK to not do this atomically since we cannot have gone multithreaded yet. set_cloexec(fd); wcstring_list_t list; for (char **ptr = argv + my_optind; *ptr; ptr++) { list.push_back(str2wcstring(*ptr)); } parser.vars().set(L"argv", ENV_DEFAULT, list); const wcstring rel_filename = str2wcstring(file); reader_push_current_filename(rel_filename.c_str()); res = reader_read(fd, {}); if (res) { debug(1, _(L"Error while reading file %ls\n"), reader_current_filename() ? reader_current_filename() : _(L"Standard input")); } reader_pop_current_filename(); } } } int exit_status = res ? STATUS_CMD_UNKNOWN : proc_get_last_status(); // TODO: The generic process-exit event is useless and unused. // Remove this in future. proc_fire_event(L"PROCESS_EXIT", event_type_t::exit, getpid(), exit_status); // Trigger any exit handlers. wcstring_list_t event_args = {to_string(exit_status)}; event_fire_generic(L"fish_exit", &event_args); restore_term_mode(); restore_term_foreground_process_group(); if (g_profiling_active) { parser.emit_profiling(s_profiling_output_filename); } history_save_all(); proc_destroy(); exit_without_destructors(exit_status); return EXIT_FAILURE; // above line should always exit }
/** * Execute selected states of the bootm command. * * Note the arguments to this state must be the first argument, Any 'bootm' * or sub-command arguments must have already been taken. * * Note that if states contains more than one flag it MUST contain * BOOTM_STATE_START, since this handles and consumes the command line args. * * Also note that aside from boot_os_fn functions and bootm_load_os no other * functions we store the return value of in 'ret' may use a negative return * value, without special handling. * * @param cmdtp Pointer to bootm command table entry * @param flag Command flags (CMD_FLAG_...) * @param argc Number of subcommand arguments (0 = no arguments) * @param argv Arguments * @param states Mask containing states to run (BOOTM_STATE_...) * @param images Image header information * @param boot_progress 1 to show boot progress, 0 to not do this * @return 0 if ok, something else on error. Some errors will cause this * function to perform a reboot! If states contains BOOTM_STATE_OS_GO * then the intent is to boot an OS, so this function will not return * unless the image type is standalone. */ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], int states, bootm_headers_t *images, int boot_progress) { boot_os_fn *boot_fn; ulong iflag = 0; int ret = 0, need_boot_fn; images->state |= states; /* * Work through the states and see how far we get. We stop on * any error. */ if (states & BOOTM_STATE_START) ret = bootm_start(cmdtp, flag, argc, argv); if (!ret && (states & BOOTM_STATE_FINDOS)) ret = bootm_find_os(cmdtp, flag, argc, argv); if (!ret && (states & BOOTM_STATE_FINDOTHER)) ret = bootm_find_other(cmdtp, flag, argc, argv); /* Load the OS */ if (!ret && (states & BOOTM_STATE_LOADOS)) { iflag = bootm_disable_interrupts(); ret = bootm_load_os(images, 0); if (ret && ret != BOOTM_ERR_OVERLAP) goto err; else if (ret == BOOTM_ERR_OVERLAP) ret = 0; } /* Relocate the ramdisk */ #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH if (!ret && (states & BOOTM_STATE_RAMDISK)) { ulong rd_len = images->rd_end - images->rd_start; ret = boot_ramdisk_high(&images->lmb, images->rd_start, rd_len, &images->initrd_start, &images->initrd_end); if (!ret) { env_set_hex("initrd_start", images->initrd_start); env_set_hex("initrd_end", images->initrd_end); } } #endif #if IMAGE_ENABLE_OF_LIBFDT && defined(CONFIG_LMB) if (!ret && (states & BOOTM_STATE_FDT)) { boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr); ret = boot_relocate_fdt(&images->lmb, &images->ft_addr, &images->ft_len); } #endif /* From now on, we need the OS boot function */ if (ret) return ret; boot_fn = bootm_os_get_boot_func(images->os.os); need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE | BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO); if (boot_fn == NULL && need_boot_fn) { if (iflag) enable_interrupts(); printf("ERROR: booting os '%s' (%d) is not supported\n", genimg_get_os_name(images->os.os), images->os.os); bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); return 1; } /* Call various other states that are not generally used */ if (!ret && (states & BOOTM_STATE_OS_CMDLINE)) ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images); if (!ret && (states & BOOTM_STATE_OS_BD_T)) ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images); if (!ret && (states & BOOTM_STATE_OS_PREP)) { #if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) if (images->os.os == IH_OS_LINUX) fixup_silent_linux(); #endif ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images); } #ifdef CONFIG_TRACE /* Pretend to run the OS, then run a user command */ if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) { char *cmd_list = env_get("fakegocmd"); ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO, images, boot_fn); if (!ret && cmd_list) ret = run_command_list(cmd_list, -1, flag); } #endif /* Check for unsupported subcommand. */ if (ret) { puts("subcommand not supported\n"); return ret; } /* Now run the OS! We hope this doesn't return */ if (!ret && (states & BOOTM_STATE_OS_GO)) ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO, images, boot_fn); /* Deal with any fallout */ err: if (iflag) enable_interrupts(); if (ret == BOOTM_ERR_UNIMPLEMENTED) bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); else if (ret == BOOTM_ERR_RESET) do_reset(cmdtp, flag, argc, argv); return ret; }
static int do_ut_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { printf("%s: Testing commands\n", __func__); run_command("env default -f -a", 0); /* run a single command */ run_command("setenv single 1", 0); assert(!strcmp("1", getenv("single"))); /* make sure that compound statements work */ #ifdef CONFIG_SYS_HUSH_PARSER run_command("if test -n ${single} ; then setenv check 1; fi", 0); assert(!strcmp("1", getenv("check"))); run_command("setenv check", 0); #endif /* commands separated by ; */ run_command_list("setenv list 1; setenv list ${list}1", -1, 0); assert(!strcmp("11", getenv("list"))); /* commands separated by \n */ run_command_list("setenv list 1\n setenv list ${list}1", -1, 0); assert(!strcmp("11", getenv("list"))); /* command followed by \n and nothing else */ run_command_list("setenv list 1${list}\n", -1, 0); assert(!strcmp("111", getenv("list"))); /* three commands in a row */ run_command_list("setenv list 1\n setenv list ${list}2; " "setenv list ${list}3", -1, 0); assert(!strcmp("123", getenv("list"))); /* a command string with \0 in it. Stuff after \0 should be ignored */ run_command("setenv list", 0); run_command_list(test_cmd, sizeof(test_cmd), 0); assert(!strcmp("123", getenv("list"))); /* * a command list where we limit execution to only the first command * using the length parameter. */ run_command_list("setenv list 1\n setenv list ${list}2; " "setenv list ${list}3", strlen("setenv list 1"), 0); assert(!strcmp("1", getenv("list"))); assert(run_command("false", 0) == 1); assert(run_command("echo", 0) == 0); assert(run_command_list("false", -1, 0) == 1); assert(run_command_list("echo", -1, 0) == 0); #ifdef CONFIG_SYS_HUSH_PARSER /* Test the 'test' command */ #define HUSH_TEST(name, expr, expected_result) \ run_command("if test " expr " ; then " \ "setenv " #name "_" #expected_result " y; else " \ "setenv " #name "_" #expected_result " n; fi", 0); \ assert(!strcmp(#expected_result, getenv(#name "_" #expected_result))); \ setenv(#name "_" #expected_result, NULL); /* Basic operators */ HUSH_TEST(streq, "aaa = aaa", y); HUSH_TEST(streq, "aaa = bbb", n); HUSH_TEST(strneq, "aaa != bbb", y); HUSH_TEST(strneq, "aaa != aaa", n); HUSH_TEST(strlt, "aaa < bbb", y); HUSH_TEST(strlt, "bbb < aaa", n); HUSH_TEST(strgt, "bbb > aaa", y); HUSH_TEST(strgt, "aaa > bbb", n); HUSH_TEST(eq, "123 -eq 123", y); HUSH_TEST(eq, "123 -eq 456", n); HUSH_TEST(ne, "123 -ne 456", y); HUSH_TEST(ne, "123 -ne 123", n); HUSH_TEST(lt, "123 -lt 456", y); HUSH_TEST(lt_eq, "123 -lt 123", n); HUSH_TEST(lt, "456 -lt 123", n); HUSH_TEST(le, "123 -le 456", y); HUSH_TEST(le_eq, "123 -le 123", y); HUSH_TEST(le, "456 -le 123", n); HUSH_TEST(gt, "456 -gt 123", y); HUSH_TEST(gt_eq, "123 -gt 123", n); HUSH_TEST(gt, "123 -gt 456", n); HUSH_TEST(ge, "456 -ge 123", y); HUSH_TEST(ge_eq, "123 -ge 123", y); HUSH_TEST(ge, "123 -ge 456", n); HUSH_TEST(z, "-z \"\"", y); HUSH_TEST(z, "-z \"aaa\"", n); HUSH_TEST(n, "-n \"aaa\"", y); HUSH_TEST(n, "-n \"\"", n); /* Inversion of simple tests */ HUSH_TEST(streq_inv, "! aaa = aaa", n); HUSH_TEST(streq_inv, "! aaa = bbb", y); HUSH_TEST(streq_inv_inv, "! ! aaa = aaa", y); HUSH_TEST(streq_inv_inv, "! ! aaa = bbb", n); /* Binary operators */ HUSH_TEST(or_0_0, "aaa != aaa -o bbb != bbb", n); HUSH_TEST(or_0_1, "aaa != aaa -o bbb = bbb", y); HUSH_TEST(or_1_0, "aaa = aaa -o bbb != bbb", y); HUSH_TEST(or_1_1, "aaa = aaa -o bbb = bbb", y); HUSH_TEST(and_0_0, "aaa != aaa -a bbb != bbb", n); HUSH_TEST(and_0_1, "aaa != aaa -a bbb = bbb", n); HUSH_TEST(and_1_0, "aaa = aaa -a bbb != bbb", n); HUSH_TEST(and_1_1, "aaa = aaa -a bbb = bbb", y); /* Inversion within binary operators */ HUSH_TEST(or_0_0_inv, "! aaa != aaa -o ! bbb != bbb", y); HUSH_TEST(or_0_1_inv, "! aaa != aaa -o ! bbb = bbb", y); HUSH_TEST(or_1_0_inv, "! aaa = aaa -o ! bbb != bbb", y); HUSH_TEST(or_1_1_inv, "! aaa = aaa -o ! bbb = bbb", n); HUSH_TEST(or_0_0_inv_inv, "! ! aaa != aaa -o ! ! bbb != bbb", n); HUSH_TEST(or_0_1_inv_inv, "! ! aaa != aaa -o ! ! bbb = bbb", y); HUSH_TEST(or_1_0_inv_inv, "! ! aaa = aaa -o ! ! bbb != bbb", y); HUSH_TEST(or_1_1_inv_inv, "! ! aaa = aaa -o ! ! bbb = bbb", y); setenv("ut_var_nonexistent", NULL); setenv("ut_var_exists", "1"); HUSH_TEST(z_varexp_quoted, "-z \"$ut_var_nonexistent\"", y); HUSH_TEST(z_varexp_quoted, "-z \"$ut_var_exists\"", n); setenv("ut_var_exists", NULL); run_command("setenv ut_var_space \" \"", 0); assert(!strcmp(getenv("ut_var_space"), " ")); run_command("setenv ut_var_test $ut_var_space", 0); assert(!getenv("ut_var_test")); run_command("setenv ut_var_test \"$ut_var_space\"", 0); assert(!strcmp(getenv("ut_var_test"), " ")); run_command("setenv ut_var_test \" 1${ut_var_space}${ut_var_space} 2 \"", 0); assert(!strcmp(getenv("ut_var_test"), " 1 2 ")); setenv("ut_var_space", NULL); setenv("ut_var_test", NULL); #ifdef CONFIG_SANDBOX /* File existence */ HUSH_TEST(e, "-e hostfs - creating_this_file_breaks_uboot_unit_test", n); run_command("sb save hostfs - creating_this_file_breaks_uboot_unit_test 0 1", 0); HUSH_TEST(e, "-e hostfs - creating_this_file_breaks_uboot_unit_test", y); /* Perhaps this could be replaced by an "rm" shell command one day */ assert(!os_unlink("creating_this_file_breaks_uboot_unit_test")); HUSH_TEST(e, "-e hostfs - creating_this_file_breaks_uboot_unit_test", n); #endif #endif printf("%s: Everything went swimmingly\n", __func__); return 0; }