Esempio n. 1
0
int main( int argc, char **argv )
{    
    struct stat tmp;
	int res=1;
	const char *cmd=0;
	int my_optind=0;

	set_main_thread();
    setup_fork_guards();
    
	wsetlocale( LC_ALL, L"" );
	is_interactive_session=1;
	program_name=L"fish";

    stat("----------FISH_HIT_MAIN----------", &tmp);

	my_optind = fish_parse_opt( argc, argv, &cmd );

	/*
	  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;
	}
    
	const struct config_paths_t paths = determine_config_directory_paths(argv[0]);
    	
	proc_init();	
	event_init();	
	wutil_init();
	//parser_init();
	builtin_init();
	function_init();
	env_init(&paths);
	reader_init();
	history_init();

    parser_t &parser = parser_t::principal_parser();

    if (g_log_forks)
        printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count);

	if( read_init(paths) )
	{
		if( cmd != 0 )
		{
			wchar_t *cmd_wcs = str2wcs( cmd );
			res = parser.eval( cmd_wcs, 0, TOP );
			free(cmd_wcs);
			reader_exit(0, 0);
		}
		else
		{
			if( my_optind == argc )
			{
				res = reader_read( STDIN_FILENO, 0 );
			}
			else
			{
				char **ptr; 
				char *file = *(argv+(my_optind++));
				int i; 
				int fd;
				wchar_t *rel_filename, *abs_filename;

                
				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 );
				}

				rel_filename = str2wcs( file );
				abs_filename = wrealpath( rel_filename, 0 );

				if( !abs_filename )
				{
					abs_filename = wcsdup(rel_filename);
				}

				reader_push_current_filename( intern( abs_filename ) );
				free( rel_filename );
				free( abs_filename );

				res = reader_read( fd, 0 );

				if( res )
				{
					debug( 1, 
					       _(L"Error while reading file %ls\n"), 
					       reader_current_filename()?reader_current_filename(): _(L"Standard input") );
				}				
				reader_pop_current_filename();
			}
		}
	}
	
	proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, getpid(), res );
	
	history_destroy();
	proc_destroy();
	builtin_destroy();
	reader_destroy();
	parser.destroy();
	wutil_destroy();
	event_destroy();
	
	env_destroy();
	
    if (g_log_forks)
        printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count);
    
	return res?STATUS_UNKNOWN_COMMAND:proc_get_last_status();	
}
Esempio n. 2
0
int job_reap( bool interactive )
{
    ASSERT_IS_MAIN_THREAD();
	job_t *jnext;	
	int found=0;
	
	static int locked = 0;
	
	locked++;	
	
	/*
	  job_read may fire an event handler, we do not want to call
	  ourselves recursively (to avoid infinite recursion).
	*/
	if( locked>1 )
		return 0;
    
    job_iterator_t jobs;
    jnext = jobs.next();
	while (jnext)
    {
        job_t *j = jnext;
        jnext = jobs.next();
		process_t *p;
		
		/*
		  If we are reaping only jobs who do not need status messages
		  sent to the console, do not consider reaping jobs that need
		  status messages
		*/
		if( (!job_get_flag( j, JOB_SKIP_NOTIFICATION ) ) && (!interactive) && (!job_get_flag( j, JOB_FOREGROUND )))
		{
			continue;
		}
	
		for( p=j->first_process; p; p=p->next )
		{
			int s;
			if( !p->completed )
				continue;
			
			if( !p->pid )
				continue;			
			
			s = p->status;
			
			proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, p->pid, ( WIFSIGNALED(s)?-1:WEXITSTATUS( s )) );			
			
			if( WIFSIGNALED(s) )
			{
				/* 
				   Ignore signal SIGPIPE.We issue it ourselves to the pipe
				   writer when the pipe reader dies.
				*/
				if( WTERMSIG(s) != SIGPIPE )
				{	
					int proc_is_job = ((p==j->first_process) && (p->next == 0));
					if( proc_is_job )
						job_set_flag( j, JOB_NOTIFIED, 1 );
					if( !job_get_flag( j, JOB_SKIP_NOTIFICATION ) )
					{
						if( proc_is_job )
							fwprintf( stdout,
									  _( L"%ls: Job %d, \'%ls\' terminated by signal %ls (%ls)" ),
									  program_name,
									  j->job_id, 
									  j->command_wcstr(),
									  sig2wcs(WTERMSIG(p->status)),
									  signal_get_desc( WTERMSIG(p->status) ) );
						else
							fwprintf( stdout,
									  _( L"%ls: Process %d, \'%ls\' from job %d, \'%ls\' terminated by signal %ls (%ls)" ),
									  program_name,
									  p->pid,
									  p->argv0(),
									  j->job_id,
									  j->command_wcstr(),
									  sig2wcs(WTERMSIG(p->status)),
									  signal_get_desc( WTERMSIG(p->status) ) );
						tputs(clr_eol,1,&writeb);
						fwprintf (stdout, L"\n" );
						found=1;						
					}
					
					/* 
					   Clear status so it is not reported more than once
					*/
					p->status = 0;
				}
			}						
		}
		
		/* 
		   If all processes have completed, tell the user the job has
		   completed and delete it from the active job list.  
		*/
		if( job_is_completed( j ) ) 
		{
			if( !job_get_flag( j, JOB_FOREGROUND) && !job_get_flag( j, JOB_NOTIFIED ) && !job_get_flag( j, JOB_SKIP_NOTIFICATION ) )
			{
				format_job_info( j, _( L"ended" ) );
				found=1;
			}
			proc_fire_event( L"JOB_EXIT", EVENT_EXIT, -j->pgid, 0 );			
			proc_fire_event( L"JOB_EXIT", EVENT_JOB_ID, j->job_id, 0 );			

			job_free(j);
		}		
		else if( job_is_stopped( j ) && !job_get_flag( j, JOB_NOTIFIED ) ) 
		{
			/* 
			   Notify the user about newly stopped jobs. 
			*/
			if( !job_get_flag( j, JOB_SKIP_NOTIFICATION ) )
			{
				format_job_info( j, _( L"stopped" ) );
				found=1;
			}			
			job_set_flag( j, JOB_NOTIFIED, 1 );
		}
	}

	if( found )
		fflush( stdout );

	locked = 0;
	
	return found;	
}
Esempio n. 3
0
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);

    if (!argv[0]) {
        static const char *dummy_argv[2] = {"fish", NULL};
        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();
    }

    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 = env_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();

    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_CMD_OK);

        // Run post-config commands specified as arguments, if any.
        if (!opts.postconfig_cmds.empty()) {
            res = run_command_list(&opts.postconfig_cmds, empty_ios);
        }

        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, empty_ios);
            reader_exit(0, 0);
        } else if (my_optind == argc) {
            // Implicitly interactive mode.
            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);

                wcstring_list_t list;
                for (char **ptr = argv + my_optind; *ptr; ptr++) {
                    list.push_back(str2wcstring(*ptr));
                }
                env_set(L"argv", ENV_DEFAULT, list);

                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_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_EXIT, getpid(), exit_status);
    event_fire_generic(L"fish_exit");

    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
}
Esempio n. 4
0
int main(int argc, char **argv)
{
    int res=1;
    int my_optind=0;

    set_main_thread();
    setup_fork_guards();

    wsetlocale(LC_ALL, L"");
    is_interactive_session=1;
    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();
    wutil_init();
    builtin_init();
    function_init();
    env_init(&paths);
    reader_init();
    history_init();
    /* For setcolor to support term256 in config.fish (#1022) */
    update_fish_term256();

    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))
    {
        /* Stop 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)
            {
                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);
                const wchar_t *abs_filename = wrealpath(rel_filename, NULL);

                if (!abs_filename)
                {
                    abs_filename = wcsdup(rel_filename.c_str());
                }

                reader_push_current_filename(intern(abs_filename));
                free((void *)abs_filename);

                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();
            }
        }
    }

    proc_fire_event(L"PROCESS_EXIT", EVENT_EXIT, getpid(), res);

    restore_term_mode();
    restore_term_foreground_process_group();
    history_destroy();
    proc_destroy();
    builtin_destroy();
    reader_destroy();
    parser.destroy();
    wutil_destroy();
    event_destroy();

    env_destroy();

    if (g_log_forks)
        printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count);

    exit_without_destructors(res ? STATUS_UNKNOWN_COMMAND : proc_get_last_status());
    return EXIT_FAILURE; //above line should always exit
}
Esempio n. 5
0
static int process_clean_after_marking(bool allow_interactive) {
    ASSERT_IS_MAIN_THREAD();
    job_t *jnext;
    int found = 0;

    // this function may fire an event handler, we do not want to call ourselves recursively (to avoid
    // infinite recursion).
    static bool locked = false;
    if (locked) {
        return 0;
    }
    locked = true;

    // this may be invoked in an exit handler, after the TERM has been torn down
    // don't try to print in that case (#3222)
    const bool interactive = allow_interactive && cur_term != NULL;


    job_iterator_t jobs;
    const size_t job_count = jobs.count();
    jnext = jobs.next();
    while (jnext) {
        job_t *j = jnext;
        jnext = jobs.next();

        // If we are reaping only jobs who do not need status messages sent to the console, do not
        // consider reaping jobs that need status messages.
        if ((!j->get_flag(JOB_SKIP_NOTIFICATION)) && (!interactive) &&
            (!j->get_flag(JOB_FOREGROUND))) {
            continue;
        }

        for (const process_ptr_t &p : j->processes) {
            int s;
            if (!p->completed) continue;

            if (!p->pid) continue;

            s = p->status;

            // TODO: The generic process-exit event is useless and unused.
            // Remove this in future.
            proc_fire_event(L"PROCESS_EXIT", EVENT_EXIT, p->pid,
                            (WIFSIGNALED(s) ? -1 : WEXITSTATUS(s)));

            // Ignore signal SIGPIPE.We issue it ourselves to the pipe writer when the pipe reader
            // dies.
            if (!WIFSIGNALED(s) || WTERMSIG(s) == SIGPIPE) {
                continue;
            }

            // Handle signals other than SIGPIPE.
            int proc_is_job = (p->is_first_in_job && p->is_last_in_job);
            if (proc_is_job) j->set_flag(JOB_NOTIFIED, true);
            if (j->get_flag(JOB_SKIP_NOTIFICATION)) {
                continue;
            }

            // Print nothing if we get SIGINT in the foreground process group, to avoid spamming
            // obvious stuff on the console (#1119). If we get SIGINT for the foreground
            // process, assume the user typed ^C and can see it working. It's possible they
            // didn't, and the signal was delivered via pkill, etc., but the SIGINT/SIGTERM
            // distinction is precisely to allow INT to be from a UI
            // and TERM to be programmatic, so this assumption is keeping with the design of
            // signals. If echoctl is on, then the terminal will have written ^C to the console.
            // If off, it won't have. We don't echo ^C either way, so as to respect the user's
            // preference.
            if (WTERMSIG(p->status) != SIGINT || !j->get_flag(JOB_FOREGROUND)) {
                if (proc_is_job) {
                    // We want to report the job number, unless it's the only job, in which case
                    // we don't need to.
                    const wcstring job_number_desc =
                        (job_count == 1) ? wcstring() : format_string(_(L"Job %d, "), j->job_id);
                    fwprintf(stdout, _(L"%ls: %ls\'%ls\' terminated by signal %ls (%ls)"),
                             program_name, job_number_desc.c_str(),
                             truncate_command(j->command()).c_str(), sig2wcs(WTERMSIG(p->status)),
                             signal_get_desc(WTERMSIG(p->status)));
                } else {
                    const wcstring job_number_desc =
                        (job_count == 1) ? wcstring() : format_string(L"from job %d, ", j->job_id);
                    const wchar_t *fmt =
                        _(L"%ls: Process %d, \'%ls\' %ls\'%ls\' terminated by signal %ls (%ls)");
                    fwprintf(stdout, fmt, program_name, p->pid, p->argv0(), job_number_desc.c_str(),
                             truncate_command(j->command()).c_str(), sig2wcs(WTERMSIG(p->status)),
                             signal_get_desc(WTERMSIG(p->status)));
                }

                if (cur_term != NULL) {
                    tputs(clr_eol, 1, &writeb);
                } else {
                    fwprintf(stdout, L"\e[K");  // no term set up - do clr_eol manually
                }
                fwprintf(stdout, L"\n");
            }
            found = 1;
            p->status = 0;  // clear status so it is not reported more than once
        }

        // If all processes have completed, tell the user the job has completed and delete it from
        // the active job list.
        if (job_is_completed(j)) {
            if (!j->get_flag(JOB_FOREGROUND) && !j->get_flag(JOB_NOTIFIED) &&
                !j->get_flag(JOB_SKIP_NOTIFICATION)) {
                format_job_info(j, JOB_ENDED);
                found = 1;
            }
            // TODO: The generic process-exit event is useless and unused.
            // Remove this in future.
            // Don't fire the exit-event for jobs with pgid -2.
            // That's our "sentinel" pgid, for jobs that don't (yet) have a pgid,
            // or jobs that consist entirely of builtins (and hence don't have a process).
            // This causes issues if fish is PID 2, which is quite common on WSL. See #4582.
            if (j->pgid != -2) {
                proc_fire_event(L"JOB_EXIT", EVENT_EXIT, -j->pgid, 0);
            }
            proc_fire_event(L"JOB_EXIT", EVENT_JOB_ID, j->job_id, 0);

            job_remove(j);
        } else if (job_is_stopped(j) && !j->get_flag(JOB_NOTIFIED)) {
            // Notify the user about newly stopped jobs.
            if (!j->get_flag(JOB_SKIP_NOTIFICATION)) {
                format_job_info(j, JOB_STOPPED);
                found = 1;
            }
            j->set_flag(JOB_NOTIFIED, true);
        }
    }

    if (found) fflush(stdout);

    locked = false;

    return found;
}
Esempio n. 6
0
int job_reap(bool interactive)
{
    ASSERT_IS_MAIN_THREAD();
    job_t *jnext;
    int found=0;

    /* job_reap may fire an event handler, we do not want to call ourselves recursively (to avoid infinite recursion). */
    static bool locked = false;
    if (locked)
    {
        return 0;
    }
    locked = true;
    
    process_mark_finished_children(false);

    /* Preserve the exit status */
    const int saved_status = proc_get_last_status();

    job_iterator_t jobs;
    const size_t job_count = jobs.count();
    jnext = jobs.next();
    while (jnext)
    {
        job_t *j = jnext;
        jnext = jobs.next();

        /*
          If we are reaping only jobs who do not need status messages
          sent to the console, do not consider reaping jobs that need
          status messages
        */
        if ((!job_get_flag(j, JOB_SKIP_NOTIFICATION)) && (!interactive) && (!job_get_flag(j, JOB_FOREGROUND)))
        {
            continue;
        }

        for (process_t *p = j->first_process; p; p=p->next)
        {
            int s;
            if (!p->completed)
                continue;

            if (!p->pid)
                continue;

            s = p->status;

            proc_fire_event(L"PROCESS_EXIT", EVENT_EXIT, p->pid, (WIFSIGNALED(s)?-1:WEXITSTATUS(s)));

            if (WIFSIGNALED(s))
            {
                /*
                   Ignore signal SIGPIPE.We issue it ourselves to the pipe
                   writer when the pipe reader dies.
                */
                if (WTERMSIG(s) != SIGPIPE)
                {
                    int proc_is_job = ((p==j->first_process) && (p->next == 0));
                    if (proc_is_job)
                        job_set_flag(j, JOB_NOTIFIED, 1);
                    if (!job_get_flag(j, JOB_SKIP_NOTIFICATION))
                    {
                        /* Print nothing if we get SIGINT in the foreground process group, to avoid spamming obvious stuff on the console (#1119). If we get SIGINT for the foreground process, assume the user typed ^C and can see it working. It's possible they didn't, and the signal was delivered via pkill, etc., but the SIGINT/SIGTERM distinction is precisely to allow INT to be from a UI and TERM to be programmatic, so this assumption is keeping with the design of signals.
                        If echoctl is on, then the terminal will have written ^C to the console. If off, it won't have. We don't echo ^C either way, so as to respect the user's preference. */
                        if (WTERMSIG(p->status) != SIGINT || ! job_get_flag(j, JOB_FOREGROUND))
                            {
                            if (proc_is_job)
                            {
                                // We want to report the job number, unless it's the only job, in which case we don't need to
                                const wcstring job_number_desc = (job_count == 1) ? wcstring() : format_string(L"Job %d, ", j->job_id);
                                fwprintf(stdout,
                                         _(L"%ls: %ls\'%ls\' terminated by signal %ls (%ls)"),
                                         program_name,
                                         job_number_desc.c_str(),
                                         truncate_command(j->command()).c_str(),
                                         sig2wcs(WTERMSIG(p->status)),
                                         signal_get_desc(WTERMSIG(p->status)));
                            }
                            else
                            {
                                const wcstring job_number_desc = (job_count == 1) ? wcstring() : format_string(L"from job %d, ", j->job_id);
                                fwprintf(stdout,
                                         _(L"%ls: Process %d, \'%ls\' %ls\'%ls\' terminated by signal %ls (%ls)"),
                                         program_name,
                                         p->pid,
                                         p->argv0(),
                                         job_number_desc.c_str(),
                                         truncate_command(j->command()).c_str(),
                                         sig2wcs(WTERMSIG(p->status)),
                                         signal_get_desc(WTERMSIG(p->status)));
                            }
                            tputs(clr_eol,1,&writeb);
                            fwprintf(stdout, L"\n");
                        }
                        found=1;
                    }

                    /*
                       Clear status so it is not reported more than once
                    */
                    p->status = 0;
                }
            }
        }

        /*
           If all processes have completed, tell the user the job has
           completed and delete it from the active job list.
        */
        if (job_is_completed(j))
        {
            if (!job_get_flag(j, JOB_FOREGROUND) && !job_get_flag(j, JOB_NOTIFIED) && !job_get_flag(j, JOB_SKIP_NOTIFICATION))
            {
                format_job_info(j, _(L"ended"), job_count);
                found=1;
            }
            proc_fire_event(L"JOB_EXIT", EVENT_EXIT, -j->pgid, 0);
            proc_fire_event(L"JOB_EXIT", EVENT_JOB_ID, j->job_id, 0);

            job_free(j);
        }
        else if (job_is_stopped(j) && !job_get_flag(j, JOB_NOTIFIED))
        {
            /*
               Notify the user about newly stopped jobs.
            */
            if (!job_get_flag(j, JOB_SKIP_NOTIFICATION))
            {
                format_job_info(j, _(L"stopped"), job_count);
                found=1;
            }
            job_set_flag(j, JOB_NOTIFIED, 1);
        }
    }

    if (found)
        fflush(stdout);

    /* Restore the exit status. */
    proc_set_last_status(saved_status);

    locked = false;

    return found;
}
Esempio n. 7
0
int main(int argc, char **argv) {
    int res = 1;
    int my_optind = 0;

    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
}