int main(int argc, char **argv) { int res=1; int my_optind=0; set_main_thread(); setup_fork_guards(); wsetlocale(LC_ALL, L""); program_name=L"fish"; //struct stat tmp; //stat("----------FISH_HIT_MAIN----------", &tmp); std::vector<std::string> cmds; my_optind = fish_parse_opt(argc, argv, &cmds); /* 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 #197, #1002 */ if (is_interactive_session) { save_term_foreground_process_group(); } const struct config_paths_t paths = determine_config_directory_paths(argv[0]); proc_init(); event_init(); builtin_init(); function_init(); env_init(&paths); reader_init(); history_init(); /* For setcolor to support term256 in config.fish (#1022) */ update_fish_color_support(); parser_t &parser = parser_t::principal_parser(); if (g_log_forks) printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count); const io_chain_t empty_ios; if (read_init(paths)) { /* Stomp the exit status of any initialization commands (#635) */ proc_set_last_status(STATUS_BUILTIN_OK); /* Run the commands specified as arguments, if any */ if (! cmds.empty()) { /* Do something nasty to support OpenSUSE assuming we're bash. This may modify cmds. */ if (is_login) { fish_xdm_login_hack_hack_hack_hack(&cmds, argc - my_optind, argv + my_optind); } for (size_t i=0; i < cmds.size(); i++) { const wcstring cmd_wcs = str2wcstring(cmds.at(i)); res = parser.eval(cmd_wcs, empty_ios, TOP); } reader_exit(0, 0); } else { if (my_optind == argc) { // Interactive mode check_running_fishd(); res = reader_read(STDIN_FILENO, empty_ios); } else { char **ptr; char *file = *(argv+(my_optind++)); int i; int fd; if ((fd = open(file, O_RDONLY)) == -1) { wperror(L"open"); return 1; } // OK to not do this atomically since we cannot have gone multithreaded yet set_cloexec(fd); if (*(argv+my_optind)) { wcstring sb; for (i=1,ptr = argv+my_optind; *ptr; i++, ptr++) { if (i != 1) sb.append(ARRAY_SEP_STR); sb.append(str2wcstring(*ptr)); } env_set(L"argv", sb.c_str(), 0); } const wcstring rel_filename = str2wcstring(file); reader_push_current_filename(rel_filename.c_str()); res = reader_read(fd, empty_ios); 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_UNKNOWN_COMMAND : proc_get_last_status(); proc_fire_event(L"PROCESS_EXIT", EVENT_EXIT, getpid(), exit_status); restore_term_mode(); restore_term_foreground_process_group(); if (g_profiling_active) { parser.emit_profiling(s_profiling_output_filename); } history_destroy(); proc_destroy(); builtin_destroy(); reader_destroy(); event_destroy(); if (g_log_forks) printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count); exit_without_destructors(exit_status); return EXIT_FAILURE; //above line should always exit }
int main(int argc, char **argv) { int res = 1; int my_optind = 0; // We can't do this at compile time due to the use of enum symbols. assert(EXPAND_SENTINAL >= EXPAND_RESERVED_BASE && EXPAND_SENTINAL <= EXPAND_RESERVED_END); assert(ANY_SENTINAL >= WILDCARD_RESERVED_BASE && ANY_SENTINAL <= WILDCARD_RESERVED_END); assert(R_SENTINAL >= INPUT_COMMON_BASE && R_SENTINAL <= INPUT_COMMON_END); program_name = L"fish"; set_main_thread(); setup_fork_guards(); setlocale(LC_ALL, ""); fish_setlocale(); // struct stat tmp; // stat("----------FISH_HIT_MAIN----------", &tmp); if (!argv[0]) { static const char *dummy_argv[2] = {"fish", NULL}; argv = (char **)dummy_argv; //!OCLINT(parameter reassignment) argc = 1; //!OCLINT(parameter reassignment) } std::vector<std::string> cmds; my_optind = fish_parse_opt(argc, argv, &cmds); // 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(); } const struct config_paths_t paths = determine_config_directory_paths(argv[0]); proc_init(); event_init(); builtin_init(); function_init(); env_init(&paths); reader_init(); history_init(); // For set_color to support term256 in config.fish (issue #1022). update_fish_color_support(); misc_init(); parser_t &parser = parser_t::principal_parser(); const io_chain_t empty_ios; if (read_init(paths)) { // Stomp the exit status of any initialization commands (issue #635). proc_set_last_status(STATUS_BUILTIN_OK); // Run the commands specified as arguments, if any. if (!cmds.empty()) { // Do something nasty to support OpenSUSE assuming we're bash. This may modify cmds. if (is_login) { fish_xdm_login_hack_hack_hack_hack(&cmds, argc - my_optind, argv + my_optind); } for (size_t i = 0; i < cmds.size(); i++) { const wcstring cmd_wcs = str2wcstring(cmds.at(i)); res = parser.eval(cmd_wcs, empty_ios, TOP); } reader_exit(0, 0); } else if (my_optind == argc) { // Interactive mode check_running_fishd(); res = reader_read(STDIN_FILENO, empty_ios); } 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); if (*(argv + my_optind)) { wcstring sb; char **ptr; int i; for (i = 1, ptr = argv + my_optind; *ptr; i++, ptr++) { if (i != 1) sb.append(ARRAY_SEP_STR); sb.append(str2wcstring(*ptr)); } env_set(L"argv", sb.c_str(), 0); } const wcstring rel_filename = str2wcstring(file); reader_push_current_filename(rel_filename.c_str()); res = reader_read(fd, empty_ios); 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_UNKNOWN_COMMAND : proc_get_last_status(); proc_fire_event(L"PROCESS_EXIT", EVENT_EXIT, getpid(), exit_status); restore_term_mode(); restore_term_foreground_process_group(); if (g_profiling_active) { parser.emit_profiling(s_profiling_output_filename); } history_destroy(); proc_destroy(); builtin_destroy(); reader_destroy(); event_destroy(); exit_without_destructors(exit_status); return EXIT_FAILURE; // above line should always exit }
/** Parse the argument list, return the index of the first non-switch arguments. */ static int fish_parse_opt(int argc, char **argv, std::vector<std::string> *cmds) { const struct option long_options[] = { { "command", required_argument, NULL, 'c' }, { "debug-level", required_argument, NULL, 'd' }, { "interactive", no_argument, NULL, 'i' } , { "login", no_argument, NULL, 'l' }, { "no-execute", no_argument, NULL, 'n' }, { "profile", required_argument, NULL, 'p' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 } }; while (1) { int opt = getopt_long(argc, argv, GETOPT_STRING, long_options, NULL); if (opt == -1) break; switch (opt) { case 0: { break; } case 'c': { cmds->push_back(optarg); break; } case 'd': { char *end; long tmp; errno = 0; tmp = strtol(optarg, &end, 10); if (tmp >= 0 && tmp <=10 && !*end && !errno) { debug_level = (int)tmp; } else { debug(0, _(L"Invalid value '%s' for debug level switch"), optarg); exit_without_destructors(1); } break; } case 'h': { cmds->push_back("__fish_print_help fish"); break; } case 'i': { is_interactive_session = 1; break; } case 'l': { is_login = 1; break; } case 'n': { no_exec = 1; break; } case 'p': { s_profiling_output_filename = optarg; g_profiling_active = true; break; } case 'v': { fwprintf(stderr, _(L"%s, version %s\n"), PACKAGE_NAME, get_fish_version()); exit_without_destructors(0); } default: { exit_without_destructors(1); } } } // If our command name begins with a dash that implies we're a login shell. is_login |= argv[0][0] == '-'; // We are an interactive session if we have not been given an explicit // command or file to execute and stdin is a tty. Note that the -i or // --interactive options also force interactive mode. if (cmds->size() == 0 && optind == argc && isatty(STDIN_FILENO)) { is_interactive_session = 1; } return optind; }
/** Connects to the fish socket and starts listening for connections */ static int get_socket(void) { // Cygwin has random problems involving sockets. When using Cygwin, // allow 20 attempts at making socket correctly. #ifdef __CYGWIN__ int attempts = 0; repeat: attempts += 1; #endif int s, len, doexit = 0; int exitcode = EXIT_FAILURE; struct sockaddr_un local; const std::string sock_name = get_socket_filename(); /* Start critical section protected by lock */ std::string lockfile; if (! acquire_socket_lock(sock_name, &lockfile)) { debug(0, L"Unable to obtain lock on socket, exiting"); exit(EXIT_FAILURE); } debug(4, L"Acquired lockfile: %s", lockfile.c_str()); local.sun_family = AF_UNIX; strcpy(local.sun_path, sock_name.c_str()); len = sizeof(local); debug(1, L"Connect to socket at %s", sock_name.c_str()); if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { wperror(L"socket"); doexit = 1; goto unlock; } /* First check whether the socket has been opened by another fishd; if so, exit with success status */ if (connect(s, (struct sockaddr *)&local, len) == 0) { debug(1, L"Socket already exists, exiting"); doexit = 1; exitcode = 0; goto unlock; } unlink(local.sun_path); if (bind(s, (struct sockaddr *)&local, len) == -1) { wperror(L"bind"); doexit = 1; goto unlock; } if (make_fd_nonblocking(s) != 0) { wperror(L"fcntl"); close(s); doexit = 1; } else if (listen(s, 64) == -1) { wperror(L"listen"); doexit = 1; } unlock: (void)unlink(lockfile.c_str()); debug(4, L"Released lockfile: %s", lockfile.c_str()); /* End critical section protected by lock */ if (doexit) { // If Cygwin, only allow normal quit when made lots of attempts. #ifdef __CYGWIN__ if (exitcode && attempts < 20) goto repeat; #endif exit_without_destructors(exitcode); } return s; }